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