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