001/*
002 * oauth2-oidc-sdk
003 *
004 * Copyright 2012-2016, Connect2id Ltd and contributors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
007 * this file except in compliance with the License. You may obtain a copy of the
008 * License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software distributed
013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
015 * specific language governing permissions and limitations under the License.
016 */
017
018package com.nimbusds.oauth2.sdk;
019
020
021import com.nimbusds.jose.util.Base64URL;
022import com.nimbusds.jwt.JWT;
023import com.nimbusds.jwt.JWTClaimsSet;
024import com.nimbusds.jwt.JWTParser;
025import com.nimbusds.jwt.SignedJWT;
026import com.nimbusds.oauth2.sdk.dpop.JWKThumbprintConfirmation;
027import com.nimbusds.oauth2.sdk.http.HTTPRequest;
028import com.nimbusds.oauth2.sdk.id.ClientID;
029import com.nimbusds.oauth2.sdk.id.State;
030import com.nimbusds.oauth2.sdk.pkce.CodeChallenge;
031import com.nimbusds.oauth2.sdk.pkce.CodeChallengeMethod;
032import com.nimbusds.oauth2.sdk.pkce.CodeVerifier;
033import com.nimbusds.oauth2.sdk.rar.AuthorizationDetail;
034import com.nimbusds.oauth2.sdk.util.*;
035import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
036import com.nimbusds.openid.connect.sdk.Prompt;
037import com.nimbusds.openid.connect.sdk.federation.trust.TrustChain;
038import net.jcip.annotations.Immutable;
039import net.minidev.json.JSONArray;
040
041import java.net.URI;
042import java.net.URISyntaxException;
043import java.util.*;
044
045
046/**
047 * Authorisation request. Used to authenticate an end-user and request the
048 * end-user's consent to grant the client access to a protected resource.
049 * Supports custom request parameters.
050 *
051 * <p>Extending classes may define additional request parameters as well as 
052 * enforce tighter requirements on the base parameters.
053 *
054 * <p>Example HTTP request:
055 *
056 * <pre>
057 * https://server.example.com/authorize?
058 * response_type=code
059 * &amp;client_id=s6BhdRkqt3
060 * &amp;state=xyz
061 * &amp;redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
062 * </pre>
063 *
064 * <p>Related specifications:
065 *
066 * <ul>
067 *     <li>OAuth 2.0 (RFC 6749), sections 4.1.1 and 4.2.1.
068 *     <li>OAuth 2.0 Multiple Response Type Encoding Practices 1.0.
069 *     <li>OAuth 2.0 Form Post Response Mode 1.0.
070 *     <li>Proof Key for Code Exchange by OAuth Public Clients (RFC 7636).
071 *     <li>OAuth 2.0 Rich Authorization Requests (RFC 9396).
072 *     <li>Resource Indicators for OAuth 2.0 (RFC 8707)
073 *     <li>OAuth 2.0 Incremental Authorization
074 *         (draft-ietf-oauth-incremental-authz-04)
075 *     <li>The OAuth 2.0 Authorization Framework: JWT Secured Authorization
076 *         Request (JAR) (RFC 9101)
077 *     <li>Financial-grade API: JWT Secured Authorization Response Mode for
078 *         OAuth 2.0 (JARM)
079 *     <li>OAuth 2.0 Demonstrating Proof-of-Possession at the Application Layer
080 *         (DPoP) (draft-ietf-oauth-dpop-16).
081 *     <li>OpenID Connect Federation 1.0, section 10.1.
082 * </ul>
083 */
084@Immutable
085public class AuthorizationRequest extends AbstractRequest {
086
087
088        /**
089         * The registered parameter names.
090         */
091        private static final Set<String> REGISTERED_PARAMETER_NAMES;
092
093
094        static {
095                Set<String> p = new HashSet<>();
096
097                p.add("response_type");
098                p.add("client_id");
099                p.add("redirect_uri");
100                p.add("scope");
101                p.add("state");
102                p.add("response_mode");
103                p.add("code_challenge");
104                p.add("code_challenge_method");
105                p.add("authorization_details");
106                p.add("resource");
107                p.add("include_granted_scopes");
108                p.add("request_uri");
109                p.add("request");
110                p.add("prompt");
111                p.add("dpop_jkt");
112                p.add("trust_chain");
113
114                REGISTERED_PARAMETER_NAMES = Collections.unmodifiableSet(p);
115        }
116        
117        
118        /**
119         * The response type (required unless in JAR).
120         */
121        private final ResponseType rt;
122
123
124        /**
125         * The client identifier (required).
126         */
127        private final ClientID clientID;
128
129
130        /**
131         * The redirection URI where the response will be sent (optional). 
132         */
133        private final URI redirectURI;
134        
135        
136        /**
137         * The scope (optional).
138         */
139        private final Scope scope;
140        
141        
142        /**
143         * The opaque value to maintain state between the request and the 
144         * callback (recommended).
145         */
146        private final State state;
147
148
149        /**
150         * The response mode (optional).
151         */
152        private final ResponseMode rm;
153
154
155        /**
156         * The authorisation code challenge for PKCE (optional).
157         */
158        private final CodeChallenge codeChallenge;
159
160
161        /**
162         * The authorisation code challenge method for PKCE (optional).
163         */
164        private final CodeChallengeMethod codeChallengeMethod;
165
166
167        /**
168         * The RAR details (optional).
169         */
170        private final List<AuthorizationDetail> authorizationDetails;
171        
172        
173        /**
174         * The resource URI(s) (optional).
175         */
176        private final List<URI> resources;
177        
178        
179        /**
180         * Indicates incremental authorisation (optional).
181         */
182        private final boolean includeGrantedScopes;
183        
184        
185        /**
186         * Request object (optional).
187         */
188        private final JWT requestObject;
189        
190        
191        /**
192         * Request object URI (optional).
193         */
194        private final URI requestURI;
195        
196        
197        /**
198         * The requested prompt (optional).
199         */
200        protected final Prompt prompt;
201        
202        
203        /**
204         * The DPoP JWK SHA-256 thumbprint (optional).
205         */
206        private final JWKThumbprintConfirmation dpopJKT;
207        
208        
209        /**
210         * The OpenID Connect Federation 1.0 trust chain (optional).
211         */
212        private final TrustChain trustChain;
213
214
215        /**
216         * Custom parameters.
217         */
218        private final Map<String,List<String>> customParams;
219
220
221        /**
222         * Builder for constructing authorisation requests.
223         */
224        public static class Builder {
225
226
227                /**
228                 * The endpoint URI (optional).
229                 */
230                private URI uri;
231
232
233                /**
234                 * The response type (required unless in JAR).
235                 */
236                private ResponseType rt;
237
238
239                /**
240                 * The client identifier (required).
241                 */
242                private final ClientID clientID;
243
244
245                /**
246                 * The redirection URI where the response will be sent
247                 * (optional).
248                 */
249                private URI redirectURI;
250
251
252                /**
253                 * The scope (optional).
254                 */
255                private Scope scope;
256
257
258                /**
259                 * The opaque value to maintain state between the request and
260                 * the callback (recommended).
261                 */
262                private State state;
263
264
265                /**
266                 * The response mode (optional).
267                 */
268                private ResponseMode rm;
269
270
271                /**
272                 * The authorisation code challenge for PKCE (optional).
273                 */
274                private CodeChallenge codeChallenge;
275
276
277                /**
278                 * The authorisation code challenge method for PKCE (optional).
279                 */
280                private CodeChallengeMethod codeChallengeMethod;
281
282
283                /**
284                 * The RAR details (optional).
285                 */
286                private List<AuthorizationDetail> authorizationDetails;
287
288
289                /**
290                 * The resource URI(s) (optional).
291                 */
292                private List<URI> resources;
293
294
295                /**
296                 * Indicates incremental authorisation (optional).
297                 */
298                private boolean includeGrantedScopes;
299
300
301                /**
302                 * Request object (optional).
303                 */
304                private JWT requestObject;
305                
306                
307                /**
308                 * Request object URI (optional).
309                 */
310                private URI requestURI;
311                
312                
313                /**
314                 * The requested prompt (optional).
315                 */
316                private Prompt prompt;
317                
318                
319                /**
320                 * The DPoP JWK SHA-256 thumbprint (optional).
321                 */
322                private JWKThumbprintConfirmation dpopJKT;
323                
324                
325                /**
326                 * The OpenID Connect Federation 1.0 trust chain (optional).
327                 */
328                private TrustChain trustChain;
329
330
331                /**
332                 * Custom parameters.
333                 */
334                private final Map<String,List<String>> customParams = new HashMap<>();
335
336
337                /**
338                 * Creates a new authorisation request builder.
339                 *
340                 * @param rt       The response type. Corresponds to the
341                 *                 {@code response_type} parameter. Must not be
342                 *                 {@code null}.
343                 * @param clientID The client identifier. Corresponds to the
344                 *                 {@code client_id} parameter. Must not be
345                 *                 {@code null}.
346                 */
347                public Builder(final ResponseType rt, final ClientID clientID) {
348
349                        if (rt == null)
350                                throw new IllegalArgumentException("The response type must not be null");
351
352                        this.rt = rt;
353
354                        if (clientID == null)
355                                throw new IllegalArgumentException("The client ID must not be null");
356
357                        this.clientID = clientID;
358                }
359                
360                
361                /**
362                 * Creates a new JWT secured authorisation request (JAR)
363                 * builder.
364                 *
365                 * @param requestObject The request object. Must not be
366                 *                      {@code null}.
367                 * @param clientID      The client ID. Must not be
368                 *                      {@code null}.
369                 */
370                public Builder(final JWT requestObject, final ClientID clientID) {
371                        
372                        if (requestObject == null)
373                                throw new IllegalArgumentException("The request object must not be null");
374                        
375                        this.requestObject = requestObject;
376                        
377                        if (clientID == null)
378                                throw new IllegalArgumentException("The client ID must not be null");
379                        
380                        this.clientID = clientID;
381                }
382                
383                
384                /**
385                 * Creates a new JWT secured authorisation request (JAR)
386                 * builder.
387                 *
388                 * @param requestURI The request object URI. Must not be
389                 *                   {@code null}.
390                 * @param clientID   The client ID. Must not be {@code null}.
391                 */
392                public Builder(final URI requestURI, final ClientID clientID) {
393                        
394                        if (requestURI == null)
395                                throw new IllegalArgumentException("The request URI must not be null");
396                        
397                        this.requestURI = requestURI;
398                        
399                        if (clientID == null)
400                                throw new IllegalArgumentException("The client ID must not be null");
401                        
402                        this.clientID = clientID;
403                }
404                
405                
406                /**
407                 * Creates a new authorisation request builder from the
408                 * specified request.
409                 *
410                 * @param request The authorisation request. Must not be
411                 *                {@code null}.
412                 */
413                public Builder(final AuthorizationRequest request) {
414                        
415                        uri = request.getEndpointURI();
416                        scope = request.getScope();
417                        rt = request.getResponseType();
418                        clientID = request.getClientID();
419                        redirectURI = request.getRedirectionURI();
420                        state = request.getState();
421                        rm = request.getResponseMode();
422                        codeChallenge = request.getCodeChallenge();
423                        codeChallengeMethod = request.getCodeChallengeMethod();
424                        authorizationDetails = request.getAuthorizationDetails();
425                        resources = request.getResources();
426                        includeGrantedScopes = request.includeGrantedScopes();
427                        requestObject = request.getRequestObject();
428                        requestURI = request.getRequestURI();
429                        prompt = request.getPrompt();
430                        dpopJKT = request.getDPoPJWKThumbprintConfirmation();
431                        trustChain = request.getTrustChain();
432                        
433                        if (request instanceof AuthenticationRequest) {
434                                AuthenticationRequest oidcRequest = (AuthenticationRequest) request;
435                                for (Map.Entry<String,List<String>> oidcParam: oidcRequest.toParameters().entrySet()) {
436                                        if (! REGISTERED_PARAMETER_NAMES.contains(oidcParam.getKey())) {
437                                                customParams.put(oidcParam.getKey(), oidcParam.getValue());
438                                        }
439                                }
440                        } else {
441                                customParams.putAll(request.getCustomParameters());
442                        }
443                }
444                
445                
446                /**
447                 * Sets the response type. Corresponds to the
448                 * {@code response_type} parameter.
449                 *
450                 * @param rt The response type. Must not be {@code null}.
451                 *
452                 * @return This builder.
453                 */
454                public Builder responseType(final ResponseType rt) {
455                        if (rt == null)
456                                throw new IllegalArgumentException("The response type must not be null");
457                        this.rt = rt;
458                        return this;
459                }
460
461
462                /**
463                 * Sets the redirection URI. Corresponds to the optional
464                 * {@code redirection_uri} parameter.
465                 *
466                 * @param redirectURI The redirection URI, {@code null} if not
467                 *                    specified.
468                 *
469                 * @return This builder.
470                 */
471                public Builder redirectionURI(final URI redirectURI) {
472                        this.redirectURI = redirectURI;
473                        return this;
474                }
475
476
477                /**
478                 * Sets the scope. Corresponds to the optional {@code scope}
479                 * parameter.
480                 *
481                 * @param scope The scope, {@code null} if not specified.
482                 *
483                 * @return This builder.
484                 */
485                public Builder scope(final Scope scope) {
486                        this.scope = scope;
487                        return this;
488                }
489
490
491                /**
492                 * Sets the state. Corresponds to the recommended {@code state}
493                 * parameter.
494                 *
495                 * @param state The state, {@code null} if not specified.
496                 *
497                 * @return This builder.
498                 */
499                public Builder state(final State state) {
500                        this.state = state;
501                        return this;
502                }
503
504
505                /**
506                 * Sets the response mode. Corresponds to the optional
507                 * {@code response_mode} parameter. Use of this parameter is
508                 * not recommended unless a non-default response mode is
509                 * requested (e.g. form_post).
510                 *
511                 * @param rm The response mode, {@code null} if not specified.
512                 *
513                 * @return This builder.
514                 */
515                public Builder responseMode(final ResponseMode rm) {
516                        this.rm = rm;
517                        return this;
518                }
519
520
521                /**
522                 * Sets the code challenge for Proof Key for Code Exchange
523                 * (PKCE) by public OAuth clients.
524                 *
525                 * @param codeChallenge       The code challenge, {@code null}
526                 *                            if not specified.
527                 * @param codeChallengeMethod The code challenge method,
528                 *                            {@code null} if not specified.
529                 *
530                 * @return This builder.
531                 */
532                @Deprecated
533                public Builder codeChallenge(final CodeChallenge codeChallenge, final CodeChallengeMethod codeChallengeMethod) {
534                        this.codeChallenge = codeChallenge;
535                        this.codeChallengeMethod = codeChallengeMethod;
536                        return this;
537                }
538
539
540                /**
541                 * Sets the code challenge for Proof Key for Code Exchange
542                 * (PKCE) by public OAuth clients.
543                 *
544                 * @param codeVerifier        The code verifier to use to
545                 *                            compute the code challenge,
546                 *                            {@code null} if PKCE is not
547                 *                            specified.
548                 * @param codeChallengeMethod The code challenge method,
549                 *                            {@code null} if not specified.
550                 *                            Defaults to
551                 *                            {@link CodeChallengeMethod#PLAIN}
552                 *                            if a code verifier is specified.
553                 *
554                 * @return This builder.
555                 */
556                public Builder codeChallenge(final CodeVerifier codeVerifier, final CodeChallengeMethod codeChallengeMethod) {
557                        if (codeVerifier != null) {
558                                CodeChallengeMethod method = codeChallengeMethod != null ? codeChallengeMethod : CodeChallengeMethod.getDefault();
559                                this.codeChallenge = CodeChallenge.compute(method, codeVerifier);
560                                this.codeChallengeMethod = method;
561                        } else {
562                                this.codeChallenge = null;
563                                this.codeChallengeMethod = null;
564                        }
565                        return this;
566                }
567
568
569                /**
570                 * Sets the Rich Authorisation Request (RAR) details.
571                 *
572                 * @param authorizationDetails The authorisation details,
573                 *                             {@code null} if not specified.
574                 *
575                 * @return This builder.
576                 */
577                public Builder authorizationDetails(final List<AuthorizationDetail> authorizationDetails) {
578                        this.authorizationDetails = authorizationDetails;
579                        return this;
580                }
581                
582                
583                /**
584                 * Sets the resource server URI.
585                 *
586                 * @param resource The resource URI, {@code null} if not
587                 *                 specified.
588                 *
589                 * @return This builder.
590                 */
591                public Builder resource(final URI resource) {
592                        if (resource != null) {
593                                this.resources = Collections.singletonList(resource);
594                        } else {
595                                this.resources = null;
596                        }
597                        return this;
598                }
599                
600                
601                /**
602                 * Sets the resource server URI(s).
603                 *
604                 * @param resources The resource URI(s), {@code null} if not
605                 *                  specified.
606                 *
607                 * @return This builder.
608                 */
609                public Builder resources(final URI ... resources) {
610                        if (resources != null) {
611                                this.resources = Arrays.asList(resources);
612                        } else {
613                                this.resources = null;
614                        }
615                        return this;
616                }
617                
618                
619                /**
620                 * Requests incremental authorisation.
621                 *
622                 * @param includeGrantedScopes {@code true} to request
623                 *                             incremental authorisation.
624                 *
625                 * @return This builder.
626                 */
627                public Builder includeGrantedScopes(final boolean includeGrantedScopes) {
628                        this.includeGrantedScopes = includeGrantedScopes;
629                        return this;
630                }
631                
632                
633                /**
634                 * Sets the request object. Corresponds to the optional
635                 * {@code request} parameter. Must not be specified together
636                 * with a request object URI.
637                 *
638                 * @param requestObject The request object, {@code null} if not
639                 *                      specified.
640                 *
641                 * @return This builder.
642                 */
643                public Builder requestObject(final JWT requestObject) {
644                        this.requestObject = requestObject;
645                        return this;
646                }
647                
648                
649                /**
650                 * Sets the request object URI. Corresponds to the optional
651                 * {@code request_uri} parameter. Must not be specified
652                 * together with a request object.
653                 *
654                 * @param requestURI The request object URI, {@code null} if
655                 *                   not specified.
656                 *
657                 * @return This builder.
658                 */
659                public Builder requestURI(final URI requestURI) {
660                        this.requestURI = requestURI;
661                        return this;
662                }
663                
664                
665                /**
666                 * Sets the requested prompt. Corresponds to the optional
667                 * {@code prompt} parameter.
668                 *
669                 * @param prompt The requested prompt, {@code null} if not
670                 *               specified.
671                 *
672                 * @return This builder.
673                 */
674                public Builder prompt(final Prompt prompt) {
675                        this.prompt = prompt;
676                        return this;
677                }
678                
679                
680                /**
681                 * Sets the requested prompt. Corresponds to the optional
682                 * {@code prompt} parameter.
683                 *
684                 * @param promptType The requested prompt types, {@code null}
685                 *                   if not specified.
686                 *
687                 * @return This builder.
688                 */
689                public Builder prompt(final Prompt.Type ... promptType) {
690                        if (promptType.length == 1 && promptType[0] == null) {
691                                return prompt((Prompt)null);
692                        } else {
693                                return prompt(new Prompt(promptType));
694                        }
695                }
696                
697                
698                /**
699                 * Sets the DPoP JWK SHA-256 thumbprint. Corresponds to the
700                 * optional {@code dpop_jkt} parameter.
701                 *
702                 * @param dpopJKT DPoP JWK SHA-256 thumbprint, {@code null} if
703                 *                not specified.
704                 *
705                 * @return This builder.
706                 */
707                public Builder dPoPJWKThumbprintConfirmation(final JWKThumbprintConfirmation dpopJKT) {
708                        this.dpopJKT = dpopJKT;
709                        return this;
710                }
711                
712                
713                /**
714                 * Sets the OpenID Connect Federation 1.0 trust chain.
715                 * Corresponds to the optional {@code trust_chain} parameter.
716                 *
717                 * @param trustChain The trust chain, {@code null} if not
718                 *                   specified.
719                 *
720                 * @return This builder.
721                 */
722                public Builder trustChain(final TrustChain trustChain) {
723                        this.trustChain = trustChain;
724                        return this;
725                }
726                
727                
728                /**
729                 * Sets a custom parameter.
730                 *
731                 * @param name   The parameter name. Must not be {@code null}.
732                 * @param values The parameter values, {@code null} if not
733                 *               specified.
734                 *
735                 * @return This builder.
736                 */
737                public Builder customParameter(final String name, final String ... values) {
738                        if (values == null || values.length == 0) {
739                                customParams.remove(name);
740                        } else {
741                                customParams.put(name, Arrays.asList(values));
742                        }
743                        return this;
744                }
745
746
747                /**
748                 * Sets the URI of the endpoint (HTTP or HTTPS) for which the
749                 * request is intended.
750                 *
751                 * @param uri The endpoint URI, {@code null} if not specified.
752                 *
753                 * @return This builder.
754                 */
755                public Builder endpointURI(final URI uri) {
756                        this.uri = uri;
757                        return this;
758                }
759
760
761                /**
762                 * Builds a new authorisation request.
763                 *
764                 * @return The authorisation request.
765                 */
766                public AuthorizationRequest build() {
767                        try {
768                                return new AuthorizationRequest(uri, rt, rm, clientID, redirectURI, scope, state,
769                                        codeChallenge, codeChallengeMethod,
770                                        authorizationDetails, resources, includeGrantedScopes,
771                                        requestObject, requestURI,
772                                        prompt, dpopJKT, trustChain,
773                                        customParams);
774                        } catch (IllegalArgumentException e) {
775                                throw new IllegalStateException(e.getMessage(), e);
776                        }
777                }
778        }
779
780
781        /**
782         * Creates a new minimal authorisation request.
783         *
784         * @param uri      The URI of the authorisation endpoint. May be
785         *                 {@code null} if the {@link #toHTTPRequest} method
786         *                 will not be used.
787         * @param rt       The response type. Corresponds to the
788         *                 {@code response_type} parameter. Must not be
789         *                 {@code null}.
790         * @param clientID The client identifier. Corresponds to the
791         *                 {@code client_id} parameter. Must not be
792         *                 {@code null}.
793         */
794        public AuthorizationRequest(final URI uri,
795                                    final ResponseType rt,
796                                    final ClientID clientID) {
797
798                this(uri, rt, null, clientID, null, null, null, null, null, null, false, null, null, null, null);
799        }
800
801
802        /**
803         * Creates a new authorisation request.
804         *
805         * @param uri                 The URI of the authorisation endpoint.
806         *                            May be {@code null} if the
807         *                            {@link #toHTTPRequest} method will not be
808         *                            used.
809         * @param rt                  The response type. Corresponds to the
810         *                            {@code response_type} parameter. Must not
811         *                            be {@code null}.
812         * @param rm                  The response mode. Corresponds to the
813         *                            optional {@code response_mode} parameter.
814         *                            Use of this parameter is not recommended
815         *                            unless a non-default response mode is
816         *                            requested (e.g. form_post).
817         * @param clientID            The client identifier. Corresponds to the
818         *                            {@code client_id} parameter. Must not be
819         *                            {@code null}.
820         * @param redirectURI         The redirection URI. Corresponds to the
821         *                            optional {@code redirect_uri} parameter.
822         *                            {@code null} if not specified.
823         * @param scope               The request scope. Corresponds to the
824         *                            optional {@code scope} parameter.
825         *                            {@code null} if not specified.
826         * @param state               The state. Corresponds to the recommended
827         *                            {@code state} parameter. {@code null} if
828         *                            not specified.
829         */
830        public AuthorizationRequest(final URI uri,
831                                    final ResponseType rt,
832                                    final ResponseMode rm,
833                                    final ClientID clientID,
834                                    final URI redirectURI,
835                                    final Scope scope,
836                                    final State state) {
837
838                this(uri, rt, rm, clientID, redirectURI, scope, state, null, null, null, false, null, null, null, null);
839        }
840
841
842        /**
843         * Creates a new authorisation request with extension and custom
844         * parameters.
845         *
846         * @param uri                  The URI of the authorisation endpoint.
847         *                             May be {@code null} if the
848         *                             {@link #toHTTPRequest} method will not
849         *                             be used.
850         * @param rt                   The response type. Corresponds to the
851         *                             {@code response_type} parameter. Must
852         *                             not be {@code null}, unless a request
853         *                             object or URI is specified.
854         * @param rm                   The response mode. Corresponds to the
855         *                             optional {@code response_mode}
856         *                             parameter. Use of this parameter is not
857         *                             recommended unless a non-default
858         *                             response mode is requested (e.g.
859         *                             form_post).
860         * @param clientID             The client identifier. Corresponds to
861         *                             the {@code client_id} parameter. Must
862         *                             not be {@code null}, unless a request
863         *                             object or URI is specified.
864         * @param redirectURI          The redirection URI. Corresponds to the
865         *                             optional {@code redirect_uri} parameter.
866         *                             {@code null} if not specified.
867         * @param scope                The request scope. Corresponds to the
868         *                             optional {@code scope} parameter.
869         *                             {@code null} if not specified.
870         * @param state                The state. Corresponds to the
871         *                             recommended {@code state} parameter.
872         *                             {@code null} if not specified.
873         * @param codeChallenge        The code challenge for PKCE,
874         *                             {@code null} if not specified.
875         * @param codeChallengeMethod  The code challenge method for PKCE,
876         *                             {@code null} if not specified.
877         * @param resources            The resource URI(s), {@code null} if not
878         *                             specified.
879         * @param includeGrantedScopes {@code true} to request incremental
880         *                             authorisation.
881         * @param requestObject        The request object. Corresponds to the
882         *                             optional {@code request} parameter. Must
883         *                             not be specified together with a request
884         *                             object URI. {@code null} if not
885         *                             specified.
886         * @param requestURI           The request object URI. Corresponds to
887         *                             the optional {@code request_uri}
888         *                             parameter. Must not be specified
889         *                             together with a request object.
890         *                             {@code null} if not specified.
891         * @param prompt               The requested prompt. Corresponds to the
892         *                             optional {@code prompt} parameter.
893         * @param customParams         Custom parameters, empty map or
894         *                             {@code null} if none.
895         */
896        @Deprecated
897        public AuthorizationRequest(final URI uri,
898                                    final ResponseType rt,
899                                    final ResponseMode rm,
900                                    final ClientID clientID,
901                                    final URI redirectURI,
902                                    final Scope scope,
903                                    final State state,
904                                    final CodeChallenge codeChallenge,
905                                    final CodeChallengeMethod codeChallengeMethod,
906                                    final List<URI> resources,
907                                    final boolean includeGrantedScopes,
908                                    final JWT requestObject,
909                                    final URI requestURI,
910                                    final Prompt prompt,
911                                    final Map<String, List<String>> customParams) {
912
913                this(uri, rt, rm, clientID, redirectURI, scope, state, codeChallenge, codeChallengeMethod,
914                        resources, includeGrantedScopes,
915                        requestObject, requestURI, prompt, null, customParams);
916        }
917
918
919        /**
920         * Creates a new authorisation request with extension and custom
921         * parameters.
922         *
923         * @param uri                  The URI of the authorisation endpoint.
924         *                             May be {@code null} if the
925         *                             {@link #toHTTPRequest} method will not
926         *                             be used.
927         * @param rt                   The response type. Corresponds to the
928         *                             {@code response_type} parameter. Must
929         *                             not be {@code null}, unless a request
930         *                             object or URI is specified.
931         * @param rm                   The response mode. Corresponds to the
932         *                             optional {@code response_mode}
933         *                             parameter. Use of this parameter is not
934         *                             recommended unless a non-default
935         *                             response mode is requested (e.g.
936         *                             form_post).
937         * @param clientID             The client identifier. Corresponds to
938         *                             the {@code client_id} parameter. Must
939         *                             not be {@code null}, unless a request
940         *                             object or URI is specified.
941         * @param redirectURI          The redirection URI. Corresponds to the
942         *                             optional {@code redirect_uri} parameter.
943         *                             {@code null} if not specified.
944         * @param scope                The request scope. Corresponds to the
945         *                             optional {@code scope} parameter.
946         *                             {@code null} if not specified.
947         * @param state                The state. Corresponds to the
948         *                             recommended {@code state} parameter.
949         *                             {@code null} if not specified.
950         * @param codeChallenge        The code challenge for PKCE,
951         *                             {@code null} if not specified.
952         * @param codeChallengeMethod  The code challenge method for PKCE,
953         *                             {@code null} if not specified.
954         * @param resources            The resource URI(s), {@code null} if not
955         *                             specified.
956         * @param includeGrantedScopes {@code true} to request incremental
957         *                             authorisation.
958         * @param requestObject        The request object. Corresponds to the
959         *                             optional {@code request} parameter. Must
960         *                             not be specified together with a request
961         *                             object URI. {@code null} if not
962         *                             specified.
963         * @param requestURI           The request object URI. Corresponds to
964         *                             the optional {@code request_uri}
965         *                             parameter. Must not be specified
966         *                             together with a request object.
967         *                             {@code null} if not specified.
968         * @param prompt               The requested prompt. Corresponds to the
969         *                             optional {@code prompt} parameter.
970         * @param dpopJKT              The DPoP JWK SHA-256 thumbprint,
971         *                             {@code null} if not specified.
972         * @param customParams         Custom parameters, empty map or
973         *                             {@code null} if none.
974         */
975        @Deprecated
976        public AuthorizationRequest(final URI uri,
977                                    final ResponseType rt,
978                                    final ResponseMode rm,
979                                    final ClientID clientID,
980                                    final URI redirectURI,
981                                    final Scope scope,
982                                    final State state,
983                                    final CodeChallenge codeChallenge,
984                                    final CodeChallengeMethod codeChallengeMethod,
985                                    final List<URI> resources,
986                                    final boolean includeGrantedScopes,
987                                    final JWT requestObject,
988                                    final URI requestURI,
989                                    final Prompt prompt,
990                                    final JWKThumbprintConfirmation dpopJKT,
991                                    final Map<String, List<String>> customParams) {
992                
993                this(uri, rt, rm, clientID, redirectURI, scope, state,
994                        codeChallenge, codeChallengeMethod,
995                        resources, includeGrantedScopes,
996                        requestObject, requestURI, prompt, dpopJKT, null, customParams);
997        }
998
999
1000        /**
1001         * Creates a new authorisation request with extension and custom
1002         * parameters.
1003         *
1004         * @param uri                  The URI of the authorisation endpoint.
1005         *                             May be {@code null} if the
1006         *                             {@link #toHTTPRequest} method will not
1007         *                             be used.
1008         * @param rt                   The response type. Corresponds to the
1009         *                             {@code response_type} parameter. Must
1010         *                             not be {@code null}, unless a request a
1011         *                             request object or URI is specified.
1012         * @param rm                   The response mode. Corresponds to the
1013         *                             optional {@code response_mode}
1014         *                             parameter. Use of this parameter is not
1015         *                             recommended unless a non-default
1016         *                             response mode is requested (e.g.
1017         *                             form_post).
1018         * @param clientID             The client identifier. Corresponds to
1019         *                             the {@code client_id} parameter. Must
1020         *                             not be {@code null}, unless a request
1021         *                             object or URI is specified.
1022         * @param redirectURI          The redirection URI. Corresponds to the
1023         *                             optional {@code redirect_uri} parameter.
1024         *                             {@code null} if not specified.
1025         * @param scope                The request scope. Corresponds to the
1026         *                             optional {@code scope} parameter.
1027         *                             {@code null} if not specified.
1028         * @param state                The state. Corresponds to the
1029         *                             recommended {@code state} parameter.
1030         *                             {@code null} if not specified.
1031         * @param codeChallenge        The code challenge for PKCE,
1032         *                             {@code null} if not specified.
1033         * @param codeChallengeMethod  The code challenge method for PKCE,
1034         *                             {@code null} if not specified.
1035         * @param resources            The resource URI(s), {@code null} if not
1036         *                             specified.
1037         * @param includeGrantedScopes {@code true} to request incremental
1038         *                             authorisation.
1039         * @param requestObject        The request object. Corresponds to the
1040         *                             optional {@code request} parameter. Must
1041         *                             not be specified together with a request
1042         *                             object URI. {@code null} if not
1043         *                             specified.
1044         * @param requestURI           The request object URI. Corresponds to
1045         *                             the optional {@code request_uri}
1046         *                             parameter. Must not be specified
1047         *                             together with a request object.
1048         *                             {@code null} if not specified.
1049         * @param prompt               The requested prompt. Corresponds to the
1050         *                             optional {@code prompt} parameter.
1051         * @param dpopJKT              The DPoP JWK SHA-256 thumbprint,
1052         *                             {@code null} if not specified.
1053         * @param trustChain           The OpenID Connect Federation 1.0 trust
1054         *                             chain, {@code null} if not specified.
1055         * @param customParams         Custom parameters, empty map or
1056         *                             {@code null} if none.
1057         */
1058        @Deprecated
1059        public AuthorizationRequest(final URI uri,
1060                                    final ResponseType rt,
1061                                    final ResponseMode rm,
1062                                    final ClientID clientID,
1063                                    final URI redirectURI,
1064                                    final Scope scope,
1065                                    final State state,
1066                                    final CodeChallenge codeChallenge,
1067                                    final CodeChallengeMethod codeChallengeMethod,
1068                                    final List<URI> resources,
1069                                    final boolean includeGrantedScopes,
1070                                    final JWT requestObject,
1071                                    final URI requestURI,
1072                                    final Prompt prompt,
1073                                    final JWKThumbprintConfirmation dpopJKT,
1074                                    final TrustChain trustChain,
1075                                    final Map<String, List<String>> customParams) {
1076
1077                this(uri, rt, rm, clientID, redirectURI, scope, state,
1078                        codeChallenge, codeChallengeMethod,
1079                        null, resources, includeGrantedScopes,
1080                        requestObject, requestURI, prompt ,dpopJKT, trustChain, customParams);
1081        }
1082
1083
1084        /**
1085         * Creates a new authorisation request with extension and custom
1086         * parameters.
1087         *
1088         * @param uri                  The URI of the authorisation endpoint.
1089         *                             May be {@code null} if the
1090         *                             {@link #toHTTPRequest} method will not
1091         *                             be used.
1092         * @param rt                   The response type. Corresponds to the
1093         *                             {@code response_type} parameter. Must
1094         *                             not be {@code null}, unless a request a
1095         *                             request object or URI is specified.
1096         * @param rm                   The response mode. Corresponds to the
1097         *                             optional {@code response_mode}
1098         *                             parameter. Use of this parameter is not
1099         *                             recommended unless a non-default
1100         *                             response mode is requested (e.g.
1101         *                             form_post).
1102         * @param clientID             The client identifier. Corresponds to
1103         *                             the {@code client_id} parameter. Must
1104         *                             not be {@code null}, unless a request
1105         *                             object or URI is specified.
1106         * @param redirectURI          The redirection URI. Corresponds to the
1107         *                             optional {@code redirect_uri} parameter.
1108         *                             {@code null} if not specified.
1109         * @param scope                The request scope. Corresponds to the
1110         *                             optional {@code scope} parameter.
1111         *                             {@code null} if not specified.
1112         * @param state                The state. Corresponds to the
1113         *                             recommended {@code state} parameter.
1114         *                             {@code null} if not specified.
1115         * @param codeChallenge        The code challenge for PKCE,
1116         *                             {@code null} if not specified.
1117         * @param codeChallengeMethod  The code challenge method for PKCE,
1118         *                             {@code null} if not specified.
1119         * @param authorizationDetails The Rich Authorisation Request (RAR)
1120         *                             details, {@code null} if not specified.
1121         * @param resources            The resource URI(s), {@code null} if not
1122         *                             specified.
1123         * @param includeGrantedScopes {@code true} to request incremental
1124         *                             authorisation.
1125         * @param requestObject        The request object. Corresponds to the
1126         *                             optional {@code request} parameter. Must
1127         *                             not be specified together with a request
1128         *                             object URI. {@code null} if not
1129         *                             specified.
1130         * @param requestURI           The request object URI. Corresponds to
1131         *                             the optional {@code request_uri}
1132         *                             parameter. Must not be specified
1133         *                             together with a request object.
1134         *                             {@code null} if not specified.
1135         * @param prompt               The requested prompt. Corresponds to the
1136         *                             optional {@code prompt} parameter.
1137         * @param dpopJKT              The DPoP JWK SHA-256 thumbprint,
1138         *                             {@code null} if not specified.
1139         * @param trustChain           The OpenID Connect Federation 1.0 trust
1140         *                             chain, {@code null} if not specified.
1141         * @param customParams         Custom parameters, empty map or
1142         *                             {@code null} if none.
1143         */
1144        public AuthorizationRequest(final URI uri,
1145                                    final ResponseType rt,
1146                                    final ResponseMode rm,
1147                                    final ClientID clientID,
1148                                    final URI redirectURI,
1149                                    final Scope scope,
1150                                    final State state,
1151                                    final CodeChallenge codeChallenge,
1152                                    final CodeChallengeMethod codeChallengeMethod,
1153                                    final List<AuthorizationDetail> authorizationDetails,
1154                                    final List<URI> resources,
1155                                    final boolean includeGrantedScopes,
1156                                    final JWT requestObject,
1157                                    final URI requestURI,
1158                                    final Prompt prompt,
1159                                    final JWKThumbprintConfirmation dpopJKT,
1160                                    final TrustChain trustChain,
1161                                    final Map<String, List<String>> customParams) {
1162
1163                super(uri);
1164
1165                if (rt == null && requestObject == null && requestURI == null)
1166                        throw new IllegalArgumentException("The response type must not be null");
1167
1168                this.rt = rt;
1169
1170                this.rm = rm;
1171
1172
1173                if (clientID == null)
1174                        throw new IllegalArgumentException("The client ID must not be null");
1175
1176                this.clientID = clientID;
1177
1178
1179                this.redirectURI = redirectURI;
1180                this.scope = scope;
1181                this.state = state;
1182
1183                this.codeChallenge = codeChallenge;
1184                this.codeChallengeMethod = codeChallengeMethod;
1185
1186                this.authorizationDetails = authorizationDetails;
1187
1188                this.resources = ResourceUtils.ensureLegalResourceURIs(resources);
1189
1190                this.includeGrantedScopes = includeGrantedScopes;
1191
1192                if (requestObject != null && requestURI != null)
1193                        throw new IllegalArgumentException("Either a request object or a request URI must be specified, but not both");
1194
1195                this.requestObject = requestObject;
1196                this.requestURI = requestURI;
1197
1198                if (requestObject instanceof SignedJWT) {
1199                        // Make sure the "sub" claim is not set to the client_id value
1200                        // https://tools.ietf.org/html/draft-ietf-oauth-jwsreq-29#section-10.8
1201                        JWTClaimsSet requestObjectClaims;
1202                        try {
1203                                requestObjectClaims = requestObject.getJWTClaimsSet();
1204                        } catch (java.text.ParseException e) {
1205                                // Should never happen
1206                                throw new IllegalArgumentException("Illegal request parameter: " + e.getMessage(), e);
1207                        }
1208                        if (clientID.getValue().equals(requestObjectClaims.getSubject())) {
1209                                throw new IllegalArgumentException("Illegal request parameter: The JWT sub (subject) claim must not equal the client_id");
1210                        }
1211                }
1212
1213                this.prompt = prompt; // technically OpenID
1214
1215                this.dpopJKT = dpopJKT;
1216
1217                this.trustChain = trustChain;
1218
1219                if (MapUtils.isNotEmpty(customParams)) {
1220                        this.customParams = Collections.unmodifiableMap(customParams);
1221                } else {
1222                        this.customParams = Collections.emptyMap();
1223                }
1224        }
1225
1226
1227        /**
1228         * Returns the registered (standard) OAuth 2.0 authorisation request
1229         * parameter names.
1230         *
1231         * @return The registered OAuth 2.0 authorisation request parameter
1232         *         names, as a unmodifiable set.
1233         */
1234        public static Set<String> getRegisteredParameterNames() {
1235
1236                return REGISTERED_PARAMETER_NAMES;
1237        }
1238
1239
1240        /**
1241         * Returns the response type. Corresponds to the {@code response_type}
1242         * parameter.
1243         *
1244         * @return The response type, may be {@code null} for a
1245         *         {@link #specifiesRequestObject() JWT secured authorisation
1246         *         request} with a {@link #getRequestObject() request} or
1247         *         {@link #getRequestURI() request_uri} parameter.
1248         */
1249        public ResponseType getResponseType() {
1250                return rt;
1251        }
1252
1253
1254        /**
1255         * Returns the optional response mode. Corresponds to the optional
1256         * {@code response_mode} parameter.
1257         *
1258         * @return The response mode, {@code null} if not specified.
1259         */
1260        public ResponseMode getResponseMode() {
1261                return rm;
1262        }
1263
1264
1265        /**
1266         * Returns the implied response mode, determined by the optional
1267         * {@code response_mode} parameter, and if that isn't specified, by
1268         * the {@code response_type}.
1269         *
1270         * <p>If the {@link ResponseMode#JWT jwt} response mode shortcut from
1271         * JARM is explicitly requested expands it to
1272         * {@link ResponseMode#QUERY_JWT query.jwt} or
1273         * {@link ResponseMode#FRAGMENT_JWT fragment.jwt} depending on the
1274         * response type ({@code response_type}).
1275         *
1276         * @return The implied response mode.
1277         */
1278        public ResponseMode impliedResponseMode() {
1279                return ResponseMode.resolve(rm, rt);
1280        }
1281
1282
1283        /**
1284         * Returns the client identifier. Corresponds to the {@code client_id}
1285         * parameter.
1286         *
1287         * @return The client identifier.
1288         */
1289        public ClientID getClientID() {
1290                return clientID;
1291        }
1292
1293
1294        /**
1295         * Returns the redirection URI. Corresponds to the optional
1296         * {@code redirection_uri} parameter.
1297         *
1298         * @return The redirection URI, {@code null} if not specified.
1299         */
1300        public URI getRedirectionURI() {
1301                return redirectURI;
1302        }
1303        
1304        
1305        /**
1306         * Returns the scope. Corresponds to the optional {@code scope}
1307         * parameter.
1308         *
1309         * @return The scope, {@code null} if not specified.
1310         */
1311        public Scope getScope() {
1312                return scope;
1313        }
1314        
1315        
1316        /**
1317         * Returns the state. Corresponds to the recommended {@code state}
1318         * parameter.
1319         *
1320         * @return The state, {@code null} if not specified.
1321         */
1322        public State getState() {
1323                return state;
1324        }
1325
1326
1327        /**
1328         * Returns the code challenge for PKCE.
1329         *
1330         * @return The code challenge, {@code null} if not specified.
1331         */
1332        public CodeChallenge getCodeChallenge() {
1333                return codeChallenge;
1334        }
1335
1336
1337        /**
1338         * Returns the code challenge method for PKCE.
1339         *
1340         * @return The code challenge method, {@code null} if not specified.
1341         */
1342        public CodeChallengeMethod getCodeChallengeMethod() {
1343                return codeChallengeMethod;
1344        }
1345
1346
1347        /**
1348         * Returns the Rich Authorisation Request (RAR) details.
1349         *
1350         * @return The authorisation details, {@code null} if not specified.
1351         */
1352        public List<AuthorizationDetail> getAuthorizationDetails() {
1353                return authorizationDetails;
1354        }
1355        
1356        
1357        /**
1358         * Returns the resource server URI.
1359         *
1360         * @return The resource URI(s), {@code null} if not specified.
1361         */
1362        public List<URI> getResources() {
1363                return resources;
1364        }
1365        
1366        
1367        /**
1368         * Returns {@code true} if incremental authorisation is requested.
1369         *
1370         * @return {@code true} if incremental authorisation is requested,
1371         *         else {@code false}.
1372         */
1373        public boolean includeGrantedScopes() {
1374                return includeGrantedScopes;
1375        }
1376        
1377        
1378        /**
1379         * Returns the request object. Corresponds to the optional
1380         * {@code request} parameter.
1381         *
1382         * @return The request object, {@code null} if not specified.
1383         */
1384        public JWT getRequestObject() {
1385                return requestObject;
1386        }
1387        
1388        
1389        /**
1390         * Returns the request object URI. Corresponds to the optional
1391         * {@code request_uri} parameter.
1392         *
1393         * @return The request object URI, {@code null} if not specified.
1394         */
1395        public URI getRequestURI() {
1396                return requestURI;
1397        }
1398        
1399        
1400        /**
1401         * Returns {@code true} if this is a JWT secured authentication
1402         * request.
1403         *
1404         * @return {@code true} if a request object via a {@code request} or
1405         *         {@code request_uri} parameter is specified, else
1406         *         {@code false}.
1407         */
1408        public boolean specifiesRequestObject() {
1409                return requestObject != null || requestURI != null;
1410        }
1411        
1412        
1413        /**
1414         * Returns the requested prompt. Corresponds to the optional
1415         * {@code prompt} parameter.
1416         *
1417         * @return The requested prompt, {@code null} if not specified.
1418         */
1419        public Prompt getPrompt() {
1420                return prompt;
1421        }
1422        
1423        
1424        /**
1425         * Returns the DPoP JWK SHA-256 thumbprint.
1426         *
1427         * @return The DPoP JWK SHA-256 thumbprint, {@code null} if not
1428         *         specified.
1429         */
1430        public JWKThumbprintConfirmation getDPoPJWKThumbprintConfirmation() {
1431                return dpopJKT;
1432        }
1433        
1434        
1435        /**
1436         * Returns the OpenID Connect Federation 1.0 trust chain.
1437         *
1438         * @return The trust chain, {@code null} if not specified.
1439         */
1440        public TrustChain getTrustChain() {
1441                return trustChain;
1442        }
1443        
1444        
1445        /**
1446         * Returns the additional custom parameters.
1447         *
1448         * @return The additional custom parameters as a unmodifiable map,
1449         *         empty map if none.
1450         */
1451        public Map<String,List<String>> getCustomParameters () {
1452                return customParams;
1453        }
1454        
1455        
1456        /**
1457         * Returns the specified custom parameter.
1458         *
1459         * @param name The parameter name. Must not be {@code null}.
1460         *
1461         * @return The parameter value(s), {@code null} if not specified.
1462         */
1463        public List<String> getCustomParameter(final String name) {
1464                return customParams.get(name);
1465        }
1466        
1467        
1468        /**
1469         * Returns the URI query parameters for this authorisation request.
1470         * Query parameters which are part of the authorisation endpoint are
1471         * not included.
1472         *
1473         * <p>Example parameters:
1474         *
1475         * <pre>
1476         * response_type = code
1477         * client_id     = s6BhdRkqt3
1478         * state         = xyz
1479         * redirect_uri  = https://client.example.com/cb
1480         * </pre>
1481         * 
1482         * @return The parameters.
1483         */
1484        public Map<String,List<String>> toParameters() {
1485                
1486                // Put custom params first, so they may be overwritten by std params
1487                Map<String, List<String>> params = new LinkedHashMap<>(customParams);
1488                
1489                params.put("client_id", Collections.singletonList(getClientID().getValue()));
1490                
1491                if (getResponseType() != null)
1492                        params.put("response_type", Collections.singletonList(getResponseType().toString()));
1493
1494                if (getResponseMode() != null)
1495                        params.put("response_mode", Collections.singletonList(getResponseMode().getValue()));
1496
1497                if (getRedirectionURI() != null)
1498                        params.put("redirect_uri", Collections.singletonList(getRedirectionURI().toString()));
1499
1500                if (getScope() != null)
1501                        params.put("scope", Collections.singletonList(getScope().toString()));
1502                
1503                if (getState() != null)
1504                        params.put("state", Collections.singletonList(getState().getValue()));
1505
1506                if (getCodeChallenge() != null) {
1507                        params.put("code_challenge", Collections.singletonList(getCodeChallenge().getValue()));
1508
1509                        if (getCodeChallengeMethod() != null) {
1510                                params.put("code_challenge_method", Collections.singletonList(getCodeChallengeMethod().getValue()));
1511                        }
1512                }
1513
1514                if (getAuthorizationDetails() != null) {
1515                        params.put("authorization_details", Collections.singletonList(AuthorizationDetail.toJSONString(getAuthorizationDetails())));
1516                }
1517                
1518                if (includeGrantedScopes())
1519                        params.put("include_granted_scopes", Collections.singletonList("true"));
1520                
1521                if (getResources() != null)
1522                        params.put("resource", URIUtils.toStringList(getResources()));
1523                
1524                if (getRequestObject() != null) {
1525                        try {
1526                                params.put("request", Collections.singletonList(getRequestObject().serialize()));
1527                        } catch (IllegalStateException e) {
1528                                throw new SerializeException("Couldn't serialize request object to JWT: " + e.getMessage(), e);
1529                        }
1530                }
1531                
1532                if (getRequestURI() != null)
1533                        params.put("request_uri", Collections.singletonList(getRequestURI().toString()));
1534                
1535                if (getPrompt() != null)
1536                        params.put("prompt", Collections.singletonList(getPrompt().toString()));
1537                
1538                if (getDPoPJWKThumbprintConfirmation() != null)
1539                        params.put("dpop_jkt", Collections.singletonList(getDPoPJWKThumbprintConfirmation().getValue().toString()));
1540                
1541                if (getTrustChain() != null) {
1542                        JSONArray jsonArray = new JSONArray();
1543                        jsonArray.addAll(getTrustChain().toSerializedJWTs());
1544                        params.put("trust_chain", Collections.singletonList(jsonArray.toJSONString()));
1545                }
1546
1547                return params;
1548        }
1549        
1550        
1551        /**
1552         * Returns the parameters for this authorisation request as a JSON Web
1553         * Token (JWT) claims set. Intended for creating a request object.
1554         *
1555         * @return The parameters as JWT claim set.
1556         */
1557        public JWTClaimsSet toJWTClaimsSet() {
1558                
1559                if (specifiesRequestObject()) {
1560                        throw new IllegalStateException("Cannot create nested JWT secured authorization request");
1561                }
1562                
1563                Map<String, List<String>> params = toParameters();
1564                
1565                JWTClaimsSet jwtClaimsSet = JWTClaimsSetUtils.toJWTClaimsSet(params);
1566                
1567                if (params.containsKey("trust_chain")) {
1568                        // JWT claim value must be a JSON array
1569                        jwtClaimsSet = new JWTClaimsSet.Builder(jwtClaimsSet)
1570                                .claim("trust_chain", getTrustChain().toSerializedJWTs())
1571                                .build();
1572                }
1573                
1574                return jwtClaimsSet;
1575        }
1576        
1577        
1578        /**
1579         * Returns the URI query string for this authorisation request.
1580         *
1581         * <p>Note that the '?' character preceding the query string in an URI
1582         * is not included in the returned string.
1583         *
1584         * <p>Example URI query string:
1585         *
1586         * <pre>
1587         * response_type=code
1588         * &amp;client_id=s6BhdRkqt3
1589         * &amp;state=xyz
1590         * &amp;redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
1591         * </pre>
1592         * 
1593         * @return The URI query string.
1594         */
1595        public String toQueryString() {
1596                
1597                Map<String, List<String>> params = new HashMap<>();
1598                if (getEndpointURI() != null) {
1599                        params.putAll(URLUtils.parseParameters(getEndpointURI().getQuery()));
1600                }
1601                params.putAll(toParameters());
1602                
1603                return URLUtils.serializeParameters(params);
1604        }
1605
1606
1607        /**
1608         * Returns the complete URI representation for this authorisation
1609         * request, consisting of the {@link #getEndpointURI authorization
1610         * endpoint URI} with the {@link #toQueryString query string} appended.
1611         *
1612         * <p>Example URI:
1613         *
1614         * <pre>
1615         * https://server.example.com/authorize?
1616         * response_type=code
1617         * &amp;client_id=s6BhdRkqt3
1618         * &amp;state=xyz
1619         * &amp;redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
1620         * </pre>
1621         *
1622         * @return The URI representation.
1623         */
1624        public URI toURI() {
1625
1626                if (getEndpointURI() == null)
1627                        throw new SerializeException("The authorization endpoint URI is not specified");
1628                
1629                StringBuilder sb = new StringBuilder(URIUtils.stripQueryString(getEndpointURI()).toString());
1630                sb.append('?');
1631                sb.append(toQueryString());
1632                try {
1633                        return new URI(sb.toString());
1634                } catch (URISyntaxException e) {
1635                        throw new SerializeException("Couldn't append query string: " + e.getMessage(), e);
1636                }
1637        }
1638        
1639        
1640        /**
1641         * Returns the matching HTTP request.
1642         *
1643         * @param method The HTTP request method which can be GET or POST. Must
1644         *               not be {@code null}.
1645         *
1646         * @return The HTTP request.
1647         */
1648        public HTTPRequest toHTTPRequest(final HTTPRequest.Method method) {
1649                
1650                if (getEndpointURI() == null)
1651                        throw new SerializeException("The endpoint URI is not specified");
1652                
1653                HTTPRequest httpRequest;
1654                if (method.equals(HTTPRequest.Method.GET)) {
1655                        httpRequest = new HTTPRequest(HTTPRequest.Method.GET, getEndpointURI());
1656                } else if (method.equals(HTTPRequest.Method.POST)) {
1657                        httpRequest = new HTTPRequest(HTTPRequest.Method.POST, getEndpointURI());
1658                } else {
1659                        throw new IllegalArgumentException("The HTTP request method must be GET or POST");
1660                }
1661                
1662                httpRequest.setQuery(toQueryString());
1663                
1664                return httpRequest;
1665        }
1666        
1667        
1668        @Override
1669        public HTTPRequest toHTTPRequest() {
1670        
1671                return toHTTPRequest(HTTPRequest.Method.GET);
1672        }
1673
1674
1675        /**
1676         * Parses an authorisation request from the specified URI query
1677         * parameters.
1678         *
1679         * <p>Example parameters:
1680         *
1681         * <pre>
1682         * response_type = code
1683         * client_id     = s6BhdRkqt3
1684         * state         = xyz
1685         * redirect_uri  = https://client.example.com/cb
1686         * </pre>
1687         *
1688         * @param params The parameters. Must not be {@code null}.
1689         *
1690         * @return The authorisation request.
1691         *
1692         * @throws ParseException If the parameters couldn't be parsed to an
1693         *                        authorisation request.
1694         */
1695        public static AuthorizationRequest parse(final Map<String,List<String>> params)
1696                throws ParseException {
1697
1698                return parse(null, params);
1699        }
1700
1701
1702        /**
1703         * Parses an authorisation request from the specified URI and query
1704         * parameters.
1705         *
1706         * <p>Example parameters:
1707         *
1708         * <pre>
1709         * response_type = code
1710         * client_id     = s6BhdRkqt3
1711         * state         = xyz
1712         * redirect_uri  = https://client.example.com/cb
1713         * </pre>
1714         *
1715         * @param uri    The URI of the authorisation endpoint. May be
1716         *               {@code null} if the {@link #toHTTPRequest()} method
1717         *               will not be used.
1718         * @param params The parameters. Must not be {@code null}.
1719         *
1720         * @return The authorisation request.
1721         *
1722         * @throws ParseException If the parameters couldn't be parsed to an
1723         *                        authorisation request.
1724         */
1725        public static AuthorizationRequest parse(final URI uri, final Map<String,List<String>> params)
1726                throws ParseException {
1727                
1728                Set<String> repeatParams = MultivaluedMapUtils.getKeysWithMoreThanOneValue(params, Collections.singleton("resource"));
1729                
1730                if (! repeatParams.isEmpty()) {
1731                        // Always result in non-redirecting error. Technically
1732                        // only duplicate client_id, state, redirect_uri,
1733                        // response_type, request_uri and request should
1734                        String msg = "Parameter(s) present more than once: " + repeatParams;
1735                        throw new ParseException(msg, OAuth2Error.INVALID_REQUEST.setDescription(msg));
1736                }
1737                
1738                // Parse response_mode, response_type, client_id, redirect_uri and state first,
1739                // needed if parsing results in a error response
1740                final ClientID clientID;
1741                URI redirectURI = null;
1742                State state = State.parse(MultivaluedMapUtils.getFirstValue(params, "state"));
1743                ResponseMode rm = null;
1744                ResponseType rt = null;
1745                
1746                // Optional response_mode
1747                String v = MultivaluedMapUtils.getFirstValue(params, "response_mode");
1748                if (StringUtils.isNotBlank(v)) {
1749                        rm = new ResponseMode(v);
1750                }
1751                
1752                // Mandatory client_id
1753                v = MultivaluedMapUtils.getFirstValue(params, "client_id");
1754                if (StringUtils.isBlank(v)) {
1755                        // No automatic redirection https://tools.ietf.org/html/rfc6749#section-4.1.2.1
1756                        String msg = "Missing client_id parameter";
1757                        throw new ParseException(msg, OAuth2Error.INVALID_REQUEST.appendDescription(": " + msg));
1758                }
1759                clientID = new ClientID(v);
1760                
1761                // Optional redirect_uri
1762                v = MultivaluedMapUtils.getFirstValue(params, "redirect_uri");
1763                if (StringUtils.isNotBlank(v)) {
1764                        try {
1765                                redirectURI = new URI(v);
1766                        } catch (URISyntaxException e) {
1767                                // No automatic redirection https://tools.ietf.org/html/rfc6749#section-4.1.2.1
1768                                String msg = "Invalid redirect_uri parameter: " + e.getMessage();
1769                                throw new ParseException(msg, OAuth2Error.INVALID_REQUEST.appendDescription(": " + msg));
1770                        }
1771                }
1772                
1773                // Mandatory response_type, unless in JAR
1774                v = MultivaluedMapUtils.getFirstValue(params, "response_type");
1775                if (StringUtils.isNotBlank(v)) {
1776                        try {
1777                                rt = ResponseType.parse(v);
1778                        } catch (ParseException e) {
1779                                // Only cause
1780                                String msg = "Invalid response_type parameter";
1781                                throw new ParseException(msg, OAuth2Error.INVALID_REQUEST.appendDescription(": " + msg),
1782                                        clientID, redirectURI, rm, state, e);
1783                        }
1784                }
1785                
1786                // Check for a JAR in request or request_uri parameters
1787                v = MultivaluedMapUtils.getFirstValue(params, "request_uri");
1788                URI requestURI = null;
1789                if (StringUtils.isNotBlank(v)) {
1790                        try {
1791                                requestURI = new URI(v);
1792                        } catch (URISyntaxException e) {
1793                                String msg = "Invalid request_uri parameter: " + e.getMessage();
1794                                throw new ParseException(msg, OAuth2Error.INVALID_REQUEST.appendDescription(": " + msg),
1795                                        clientID, redirectURI, ResponseMode.resolve(rm, rt), state, e);
1796                        }
1797                }
1798                
1799                v = MultivaluedMapUtils.getFirstValue(params, "request");
1800                
1801                JWT requestObject = null;
1802                
1803                if (StringUtils.isNotBlank(v)) {
1804                        
1805                        // request_object and request_uri must not be present at the same time
1806                        if (requestURI != null) {
1807                                String msg = "Invalid request: Found mutually exclusive request and request_uri parameters";
1808                                throw new ParseException(msg, OAuth2Error.INVALID_REQUEST.appendDescription(": " + msg),
1809                                        clientID, redirectURI, ResponseMode.resolve(rm, rt), state, null);
1810                        }
1811                        
1812                        try {
1813                                requestObject = JWTParser.parse(v);
1814                                
1815                                if (requestObject instanceof SignedJWT) {
1816                                        // Make sure the "sub" claim is not set to the client_id value
1817                                        // https://tools.ietf.org/html/draft-ietf-oauth-jwsreq-29#section-10.8
1818                                        JWTClaimsSet requestObjectClaims = requestObject.getJWTClaimsSet();
1819                                        if (clientID.getValue().equals(requestObjectClaims.getSubject())) {
1820                                                throw new java.text.ParseException("The JWT sub (subject) claim must not equal the client_id", 0);
1821                                        }
1822                                }
1823                                
1824                        } catch (java.text.ParseException e) {
1825                                String msg = "Invalid request parameter: " + e.getMessage();
1826                                throw new ParseException(msg, OAuth2Error.INVALID_REQUEST.appendDescription(": " + msg),
1827                                        clientID, redirectURI, ResponseMode.resolve(rm, rt), state, e);
1828                        }
1829                }
1830
1831                // Response type mandatory, unless in JAR
1832                if (rt == null && requestObject == null && requestURI == null) {
1833                        String msg = "Missing response_type parameter";
1834                        throw new ParseException(msg, OAuth2Error.INVALID_REQUEST.appendDescription(": " + msg),
1835                                clientID, redirectURI, ResponseMode.resolve(rm, null), state, null);
1836                }
1837
1838
1839                // Parse optional scope
1840                v = MultivaluedMapUtils.getFirstValue(params, "scope");
1841
1842                Scope scope = null;
1843
1844                if (StringUtils.isNotBlank(v))
1845                        scope = Scope.parse(v);
1846
1847
1848                // Parse optional code challenge and method for PKCE
1849                CodeChallenge codeChallenge = null;
1850                CodeChallengeMethod codeChallengeMethod = null;
1851
1852                v = MultivaluedMapUtils.getFirstValue(params, "code_challenge");
1853
1854                if (StringUtils.isNotBlank(v))
1855                        codeChallenge = CodeChallenge.parse(v);
1856
1857                if (codeChallenge != null) {
1858
1859                        v = MultivaluedMapUtils.getFirstValue(params, "code_challenge_method");
1860
1861                        if (StringUtils.isNotBlank(v))
1862                                codeChallengeMethod = CodeChallengeMethod.parse(v);
1863                }
1864
1865
1866                List<AuthorizationDetail> authorizationDetails = null;
1867                v = MultivaluedMapUtils.getFirstValue(params, "authorization_details");
1868                if (StringUtils.isNotBlank(v)) {
1869                        authorizationDetails = AuthorizationDetail.parseList(v);
1870                }
1871                
1872                
1873                List<URI> resources;
1874                try {
1875                        resources = ResourceUtils.parseResourceURIs(params.get("resource"));
1876                } catch (ParseException e) {
1877                        throw new ParseException(e.getMessage(), OAuth2Error.INVALID_TARGET.setDescription(e.getMessage()),
1878                                clientID, redirectURI, ResponseMode.resolve(rm, rt), state, e);
1879                }
1880                
1881                boolean includeGrantedScopes = false;
1882                v = MultivaluedMapUtils.getFirstValue(params, "include_granted_scopes");
1883                if ("true".equals(v)) {
1884                        includeGrantedScopes = true;
1885                }
1886                
1887                Prompt prompt;
1888                try {
1889                        prompt = Prompt.parse(MultivaluedMapUtils.getFirstValue(params, "prompt"));
1890                        
1891                } catch (ParseException e) {
1892                        String msg = "Invalid prompt parameter: " + e.getMessage();
1893                        throw new ParseException(msg, OAuth2Error.INVALID_REQUEST.appendDescription(": " + msg),
1894                                clientID, redirectURI, ResponseMode.resolve(rm, rt), state, e);
1895                }
1896                
1897                JWKThumbprintConfirmation dpopJKT = null;
1898                v = MultivaluedMapUtils.getFirstValue(params, "dpop_jkt");
1899                if (StringUtils.isNotBlank(v)) {
1900                        dpopJKT = new JWKThumbprintConfirmation(new Base64URL(v));
1901                }
1902                
1903                TrustChain trustChain = null;
1904                v = MultivaluedMapUtils.getFirstValue(params, "trust_chain");
1905                if (StringUtils.isNotBlank(v)) {
1906                        JSONArray jsonArray = JSONArrayUtils.parse(v);
1907                        trustChain = TrustChain.parseSerialized(JSONArrayUtils.toStringList(jsonArray));
1908                }
1909                
1910                // Parse custom parameters
1911                Map<String,List<String>> customParams = null;
1912
1913                for (Map.Entry<String,List<String>> p: params.entrySet()) {
1914
1915                        if (! REGISTERED_PARAMETER_NAMES.contains(p.getKey())) {
1916                                // We have a custom parameter
1917                                if (customParams == null) {
1918                                        customParams = new HashMap<>();
1919                                }
1920                                customParams.put(p.getKey(), p.getValue());
1921                        }
1922                }
1923
1924
1925                return new AuthorizationRequest(uri, rt, rm, clientID, redirectURI, scope, state,
1926                        codeChallenge, codeChallengeMethod,
1927                        authorizationDetails, resources, includeGrantedScopes,
1928                        requestObject, requestURI,
1929                        prompt, dpopJKT, trustChain,
1930                        customParams);
1931        }
1932
1933
1934        /**
1935         * Parses an authorisation request from the specified URI query string.
1936         *
1937         * <p>Example URI query string:
1938         *
1939         * <pre>
1940         * response_type=code
1941         * &amp;client_id=s6BhdRkqt3
1942         * &amp;state=xyz
1943         * &amp;redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
1944         * </pre>
1945         *
1946         * @param query The URI query string. Must not be {@code null}.
1947         *
1948         * @return The authorisation request.
1949         *
1950         * @throws ParseException If the query string couldn't be parsed to an
1951         *                        authorisation request.
1952         */
1953        public static AuthorizationRequest parse(final String query)
1954                throws ParseException {
1955
1956                return parse(null, URLUtils.parseParameters(query));
1957        }
1958        
1959        
1960        /**
1961         * Parses an authorisation request from the specified URI and query
1962         * string.
1963         *
1964         * <p>Example URI query string:
1965         *
1966         * <pre>
1967         * response_type=code
1968         * &amp;client_id=s6BhdRkqt3
1969         * &amp;state=xyz
1970         * &amp;redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
1971         * </pre>
1972         *
1973         * @param uri   The URI of the authorisation endpoint. May be 
1974         *              {@code null} if the {@link #toHTTPRequest()} method
1975         *              will not be used.
1976         * @param query The URI query string. Must not be {@code null}.
1977         *
1978         * @return The authorisation request.
1979         *
1980         * @throws ParseException If the query string couldn't be parsed to an 
1981         *                        authorisation request.
1982         */
1983        public static AuthorizationRequest parse(final URI uri, final String query)
1984                throws ParseException {
1985        
1986                return parse(uri, URLUtils.parseParameters(query));
1987        }
1988
1989
1990        /**
1991         * Parses an authorisation request from the specified URI.
1992         *
1993         * <p>Example URI:
1994         *
1995         * <pre>
1996         * https://server.example.com/authorize?
1997         * response_type=code
1998         * &amp;client_id=s6BhdRkqt3
1999         * &amp;state=xyz
2000         * &amp;redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
2001         * </pre>
2002         *
2003         * @param uri The URI. Must not be {@code null}.
2004         *
2005         * @return The authorisation request.
2006         *
2007         * @throws ParseException If the URI couldn't be parsed to an
2008         *                        authorisation request.
2009         */
2010        public static AuthorizationRequest parse(final URI uri)
2011                throws ParseException {
2012
2013                return parse(URIUtils.getBaseURI(uri), URLUtils.parseParameters(uri.getRawQuery()));
2014        }
2015        
2016        
2017        /**
2018         * Parses an authorisation request from the specified HTTP request.
2019         *
2020         * <p>Example HTTP request (GET):
2021         *
2022         * <pre>
2023         * https://server.example.com/authorize?
2024         * response_type=code
2025         * &amp;client_id=s6BhdRkqt3
2026         * &amp;state=xyz
2027         * &amp;redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
2028         * </pre>
2029         *
2030         * @param httpRequest The HTTP request. Must not be {@code null}.
2031         *
2032         * @return The authorisation request.
2033         *
2034         * @throws ParseException If the HTTP request couldn't be parsed to an 
2035         *                        authorisation request.
2036         */
2037        public static AuthorizationRequest parse(final HTTPRequest httpRequest) 
2038                throws ParseException {
2039                
2040                String query = httpRequest.getQuery();
2041                
2042                if (query == null)
2043                        throw new ParseException("Missing URI query string");
2044                
2045                return parse(URIUtils.getBaseURI(httpRequest.getURI()), query);
2046        }
2047}