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