001/* 002 * Copyright 2015 The AppAuth for Android Authors. All Rights Reserved. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the 010 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 011 * express or implied. See the License for the specific language governing permissions and 012 * limitations under the License. 013 */ 014 015package net.openid.appauth; 016 017import static net.openid.appauth.AdditionalParamsProcessor.builtInParams; 018import static net.openid.appauth.AdditionalParamsProcessor.checkAdditionalParams; 019import static net.openid.appauth.Preconditions.checkArgument; 020import static net.openid.appauth.Preconditions.checkNotEmpty; 021import static net.openid.appauth.Preconditions.checkNotNull; 022import static net.openid.appauth.Preconditions.checkNullOrNotEmpty; 023 024import android.net.Uri; 025import android.text.TextUtils; 026import androidx.annotation.NonNull; 027import androidx.annotation.Nullable; 028import androidx.annotation.VisibleForTesting; 029 030import net.openid.appauth.internal.UriUtil; 031import org.json.JSONException; 032import org.json.JSONObject; 033 034import java.util.Arrays; 035import java.util.Collections; 036import java.util.HashMap; 037import java.util.Map; 038import java.util.Map.Entry; 039import java.util.Set; 040 041/** 042 * An OAuth2 authorization request. 043 * 044 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 4 045 * <https://tools.ietf.org/html/rfc6749#section-4>" 046 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 4.1.1 047 * <https://tools.ietf.org/html/rfc6749#section-4.1.1>" 048 */ 049public class AuthorizationRequest implements AuthorizationManagementRequest { 050 051 /** 052 * SHA-256 based code verifier challenge method. 053 * 054 * @see "Proof Key for Code Exchange by OAuth Public Clients (RFC 7636), Section 4.3 055 * <https://tools.ietf.org/html/rfc7636#section-4.3>" 056 */ 057 public static final String CODE_CHALLENGE_METHOD_S256 = "S256"; 058 059 /** 060 * Plain-text code verifier challenge method. This is only used by AppAuth for Android if 061 * SHA-256 is not supported on this platform. 062 * 063 * @see "Proof Key for Code Exchange by OAuth Public Clients (RFC 7636), Section 4.4 064 * <https://tools.ietf.org/html/rfc7636#section-4.4>" 065 */ 066 public static final String CODE_CHALLENGE_METHOD_PLAIN = "plain"; 067 068 /** 069 * All spec-defined values for the OpenID Connect 1.0 `display` parameter. 070 * 071 * @see Builder#setDisplay(String) 072 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 073 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 074 */ 075 // SuppressWarnings justification: the constants defined are not directly used by the library, 076 // existing only for convenience of the developer. 077 @SuppressWarnings("unused") 078 public static final class Display { 079 080 /** 081 * The Authorization Server _SHOULD_ display the authentication and consent UI 082 * consistent with a full User Agent page view. If the display parameter is not specified, 083 * this is the default display mode. 084 */ 085 public static final String PAGE = "page"; 086 087 /** 088 * The Authorization Server _SHOULD_ display the authentication and consent UI 089 * consistent with a popup User Agent window. The popup User Agent window should be of an 090 * appropriate size for a login-focused dialog and should not obscure the entire window that 091 * it is popping up over. 092 */ 093 public static final String POPUP = "popup"; 094 095 /** 096 * The Authorization Server _SHOULD_ display the authentication and consent UI 097 * consistent with a device that leverages a touch interface. 098 */ 099 public static final String TOUCH = "touch"; 100 101 /** 102 * The Authorization Server _SHOULD_ display the authentication and consent UI 103 * consistent with a "feature phone" type display. 104 */ 105 public static final String WAP = "wap"; 106 } 107 108 /** 109 * All spec-defined values for the OpenID Connect 1.0 `prompt` parameter. 110 * 111 * @see Builder#setPrompt(String) 112 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 113 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 114 */ 115 // SuppressWarnings justification: the constants defined are not directly used by the library, 116 // existing only for convenience of the developer. 117 @SuppressWarnings("unused") 118 public static final class Prompt { 119 120 /** 121 * The Authorization Server _MUST NOT_ display any authentication or consent user 122 * interface pages. An error is returned if an End-User is not already authenticated or the 123 * Client does not have pre-configured consent for the requested Claims or does not fulfill 124 * other conditions for processing the request. The error code will typically be 125 * `login_required`, `interaction_required`, or another code defined in 126 * [OpenID Connect Core 1.0, Section 3.1.2.6]( 127 * https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.6). This can be 128 * used as a method to check for existing authentication and/or consent. 129 * 130 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 131 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 132 * @see "OpenID Connect Core 1.0, Section 3.1.2.6 133 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.6>" 134 */ 135 public static final String NONE = "none"; 136 137 /** 138 * The Authorization Server _SHOULD_ prompt the End-User for re-authentication. If 139 * it cannot re-authenticate the End-User, it _MUST_ return an error, typically 140 * `login_required`. 141 * 142 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 143 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 144 * @see "OpenID Connect Core 1.0, Section 3.1.2.6 145 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.6>" 146 */ 147 public static final String LOGIN = "login"; 148 149 /** 150 * The Authorization Server _SHOULD_ prompt the End-User for consent before 151 * returning information to the Client. If it cannot obtain consent, it _MUST_ 152 * return an error, typically `consent_required`. 153 * 154 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 155 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 156 * @see "OpenID Connect Core 1.0, Section 3.1.2.6 157 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.6>" 158 */ 159 public static final String CONSENT = "consent"; 160 161 /** 162 * The Authorization Server _SHOULD_ prompt the End-User to select a user account. 163 * This enables an End-User who has multiple accounts at the Authorization Server to select 164 * amongst the multiple accounts that they might have current sessions for. If it cannot 165 * obtain an account selection choice made by the End-User, it MUST return an error, 166 * typically `account_selection_required`. 167 * 168 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 169 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 170 * @see "OpenID Connect Core 1.0, Section 3.1.2.6 171 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.6>" 172 */ 173 public static final String SELECT_ACCOUNT = "select_account"; 174 } 175 176 /** 177 * All spec-defined values for the OAuth2 / OpenID Connect 1.0 `scope` parameter. 178 * 179 * @see Builder#setScope(String) 180 * @see "OpenID Connect Core 1.0, Section 5.4 181 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.5.4>" 182 */ 183 // SuppressWarnings justification: the constants defined are not directly used by the library, 184 // existing only for convenience of the developer. 185 @SuppressWarnings("unused") 186 public static final class Scope { 187 /** 188 * A scope for the authenticated user's mailing address. 189 * 190 * @see "OpenID Connect Core 1.0, Section 5.4 191 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.5.4>" 192 */ 193 public static final String ADDRESS = "address"; 194 195 /** 196 * A scope for the authenticated user's email address. 197 * 198 * @see "OpenID Connect Core 1.0, Section 5.4 199 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.5.4>" 200 */ 201 public static final String EMAIL = "email"; 202 203 /** 204 * A scope for requesting an OAuth 2.0 refresh token to be issued, that can be used to 205 * obtain an Access Token that grants access to the End-User's UserInfo Endpoint even 206 * when the End-User is not present (not logged in). 207 * 208 * @see "OpenID Connect Core 1.0, Section 11 209 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.11>" 210 */ 211 public static final String OFFLINE_ACCESS = "offline_access"; 212 213 /** 214 * A scope for OpenID based authorization. 215 * 216 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 217 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 218 */ 219 public static final String OPENID = "openid"; 220 221 /** 222 * A scope for the authenticated user's phone number. 223 * 224 * @see "OpenID Connect Core 1.0, Section 5.4 225 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.5.4>" 226 */ 227 public static final String PHONE = "phone"; 228 229 /** 230 * A scope for the authenticated user's basic profile information. 231 * 232 * @see "OpenID Connect Core 1.0, Section 5.4 233 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.5.4>" 234 */ 235 public static final String PROFILE = "profile"; 236 } 237 238 /** 239 * All spec-defined values for the OAuth2 / OpenID Connect `response_mode` parameter. 240 * 241 * @see Builder#setResponseMode(String) 242 * @see "OAuth 2.0 Multiple Response Type Encoding Practices, Section 2.1 243 * <http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#rfc.section.2.1>" 244 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 245 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 246 */ 247 // SuppressWarnings justification: the constants defined are not directly used by the library, 248 // existing only for convenience of the developer. 249 @SuppressWarnings("unused") 250 public static final class ResponseMode { 251 /** 252 * Instructs the authorization server to send response parameters using 253 * the query portion of the redirect URI. 254 * 255 * @see "OAuth 2.0 Multiple Response Type Encoding Practices, Section 2.1 256 * <http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#rfc.section.2.1>" 257 */ 258 public static final String QUERY = "query"; 259 260 /** 261 * Instructs the authorization server to send response parameters using 262 * the fragment portion of the redirect URI. 263 * @see "OAuth 2.0 Multiple Response Type Encoding Practices, Section 2.1 264 * <http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#rfc.section.2.1>" 265 */ 266 public static final String FRAGMENT = "fragment"; 267 } 268 269 @VisibleForTesting 270 static final String PARAM_CLIENT_ID = "client_id"; 271 272 @VisibleForTesting 273 static final String PARAM_CODE_CHALLENGE = "code_challenge"; 274 275 @VisibleForTesting 276 static final String PARAM_CODE_CHALLENGE_METHOD = "code_challenge_method"; 277 278 @VisibleForTesting 279 static final String PARAM_DISPLAY = "display"; 280 281 @VisibleForTesting 282 static final String PARAM_LOGIN_HINT = "login_hint"; 283 284 @VisibleForTesting 285 static final String PARAM_PROMPT = "prompt"; 286 287 @VisibleForTesting 288 static final String PARAM_UI_LOCALES = "ui_locales"; 289 290 @VisibleForTesting 291 static final String PARAM_REDIRECT_URI = "redirect_uri"; 292 293 @VisibleForTesting 294 static final String PARAM_RESPONSE_MODE = "response_mode"; 295 296 @VisibleForTesting 297 static final String PARAM_RESPONSE_TYPE = "response_type"; 298 299 @VisibleForTesting 300 static final String PARAM_SCOPE = "scope"; 301 302 @VisibleForTesting 303 static final String PARAM_STATE = "state"; 304 305 @VisibleForTesting 306 static final String PARAM_NONCE = "nonce"; 307 308 @VisibleForTesting 309 static final String PARAM_CLAIMS = "claims"; 310 311 @VisibleForTesting 312 static final String PARAM_CLAIMS_LOCALES = "claims_locales"; 313 314 private static final Set<String> BUILT_IN_PARAMS = builtInParams( 315 PARAM_CLIENT_ID, 316 PARAM_CODE_CHALLENGE, 317 PARAM_CODE_CHALLENGE_METHOD, 318 PARAM_DISPLAY, 319 PARAM_LOGIN_HINT, 320 PARAM_PROMPT, 321 PARAM_UI_LOCALES, 322 PARAM_REDIRECT_URI, 323 PARAM_RESPONSE_MODE, 324 PARAM_RESPONSE_TYPE, 325 PARAM_SCOPE, 326 PARAM_STATE, 327 PARAM_CLAIMS, 328 PARAM_CLAIMS_LOCALES); 329 330 private static final String KEY_CONFIGURATION = "configuration"; 331 private static final String KEY_CLIENT_ID = "clientId"; 332 private static final String KEY_DISPLAY = "display"; 333 private static final String KEY_LOGIN_HINT = "login_hint"; 334 private static final String KEY_PROMPT = "prompt"; 335 private static final String KEY_UI_LOCALES = "ui_locales"; 336 private static final String KEY_RESPONSE_TYPE = "responseType"; 337 private static final String KEY_REDIRECT_URI = "redirectUri"; 338 private static final String KEY_SCOPE = "scope"; 339 private static final String KEY_STATE = "state"; 340 private static final String KEY_NONCE = "nonce"; 341 private static final String KEY_CODE_VERIFIER = "codeVerifier"; 342 private static final String KEY_CODE_VERIFIER_CHALLENGE = "codeVerifierChallenge"; 343 private static final String KEY_CODE_VERIFIER_CHALLENGE_METHOD = "codeVerifierChallengeMethod"; 344 private static final String KEY_RESPONSE_MODE = "responseMode"; 345 private static final String KEY_CLAIMS = "claims"; 346 private static final String KEY_CLAIMS_LOCALES = "claimsLocales"; 347 private static final String KEY_ADDITIONAL_PARAMETERS = "additionalParameters"; 348 349 /** 350 * The service's {@link AuthorizationServiceConfiguration configuration}. 351 * This configuration specifies how to connect to a particular OAuth provider. 352 * Configurations may be 353 * {@link 354 * AuthorizationServiceConfiguration#AuthorizationServiceConfiguration(Uri, Uri, Uri, Uri)} 355 * created manually}, or {@link AuthorizationServiceConfiguration#fetchFromUrl(Uri, 356 * AuthorizationServiceConfiguration.RetrieveConfigurationCallback)} via an OpenID Connect 357 * Discovery Document}. 358 */ 359 @NonNull 360 public final AuthorizationServiceConfiguration configuration; 361 362 /** 363 * The client identifier. 364 * 365 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 4 366 * <https://tools.ietf.org/html/rfc6749#section-4>" 367 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 4.1.1 368 * <https://tools.ietf.org/html/rfc6749#section-4.1.1>" 369 */ 370 @NonNull 371 public final String clientId; 372 373 /** 374 * The OpenID Connect 1.0 `display` parameter. This is a string that specifies how the 375 * Authorization Server displays the authentication and consent user interface pages to the 376 * End-User. 377 * 378 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 379 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 380 */ 381 @Nullable 382 public final String display; 383 384 385 /** 386 * The OpenID Connect 1.0 `login_hint` parameter. This is a string hint to the 387 * Authorization Server about the login identifier the End-User might use to log in, typically 388 * collected directly from the user in an identifier-first authentication flow. 389 * 390 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 391 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 392 */ 393 @Nullable 394 public final String loginHint; 395 396 /** 397 * The OpenID Connect 1.0 `prompt` parameter. This is a space delimited, case sensitive 398 * list of ASCII strings that specifies whether the Authorization Server prompts the End-User 399 * for re-authentication and consent. 400 * 401 * @see Prompt 402 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 403 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 404 */ 405 @Nullable 406 public final String prompt; 407 408 /** 409 * The OpenID Connect 1.0 `ui_locales` parameter. This is a space-separated list of 410 * BCP47 [RFC5646] language tag values, ordered by preference. It represents End-User's 411 * preferred languages and scripts for the user interface. 412 * 413 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 414 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 415 */ 416 @Nullable 417 public final String uiLocales; 418 419 /** 420 * The expected response type. 421 * 422 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 3.1.1 423 * <https://tools.ietf.org/html/rfc6749#section-3.1.1>" 424 * @see "OpenID Connect Core 1.0, Section 3 425 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3>" 426 */ 427 @NonNull 428 public final String responseType; 429 430 /** 431 * The client's redirect URI. 432 * 433 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 3.1.2 434 * <https://tools.ietf.org/html/rfc6749#section-3.1.2>" 435 */ 436 @NonNull 437 public final Uri redirectUri; 438 439 /** 440 * The optional set of scopes expressed as a space-delimited, case-sensitive string. 441 * 442 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 3.1.2 443 * <https://tools.ietf.org/html/rfc6749#section-3.1.2>" 444 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 3.3 445 * <https://tools.ietf.org/html/rfc6749#section-3.3>" 446 */ 447 @Nullable 448 public final String scope; 449 450 /** 451 * An opaque value used by the client to maintain state between the request and callback. If 452 * this value is not explicitly set, this library will automatically add state and perform 453 * appropriate validation of the state in the authorization response. It is recommended that 454 * the default implementation of this parameter be used wherever possible. Typically used to 455 * prevent CSRF attacks, as recommended in 456 * [RFC6819 Section 5.3.5](https://tools.ietf.org/html/rfc6819#section-5.3.5). 457 * 458 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 4.1.1 459 * <https://tools.ietf.org/html/rfc6749#section-4.1.1>" 460 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 5.3.5 461 * <https://tools.ietf.org/html/rfc6749#section-5.3.5>" 462 */ 463 @Nullable 464 public final String state; 465 466 /** 467 * String value used to associate a Client session with an ID Token, and to mitigate replay 468 * attacks. The value is passed through unmodified from the Authentication Request to the ID 469 * Token. If this value is not explicitly set, this library will automatically add nonce and 470 * perform appropriate validation of the ID Token. It is recommended that the default 471 * implementation of this parameter be used wherever possible. 472 * 473 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 474 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 475 */ 476 @Nullable 477 public final String nonce; 478 479 /** 480 * The proof key for code exchange. This is an opaque value used to associate an authorization 481 * request with a subsequent code exchange, in order to prevent any eavesdropping party from 482 * intercepting and using the code before the original requestor. If PKCE is disabled due to 483 * a non-compliant authorization server which rejects requests with PKCE parameters present, 484 * this value will be `null`. 485 * 486 * @see Builder#setCodeVerifier(String) 487 * @see Builder#setCodeVerifier(String, String, String) 488 * @see "Proof Key for Code Exchange by OAuth Public Clients (RFC 7636) 489 * <https://tools.ietf.org/html/rfc7636>" 490 */ 491 @Nullable 492 public final String codeVerifier; 493 494 /** 495 * The challenge derived from the {@link #codeVerifier code verifier}, using the 496 * {@link #codeVerifierChallengeMethod challenge method}. If a code verifier is not being 497 * used for this request, this value will be `null`. 498 * 499 * @see Builder#setCodeVerifier(String) 500 * @see Builder#setCodeVerifier(String, String, String) 501 * @see "Proof Key for Code Exchange by OAuth Public Clients (RFC 7636) 502 * <https://tools.ietf.org/html/rfc7636>" 503 */ 504 @Nullable 505 public final String codeVerifierChallenge; 506 507 /** 508 * The challenge method used to generate a {@link #codeVerifierChallenge challenge} from 509 * the {@link #codeVerifier code verifier}. If a code verifier is not being used for this 510 * request, this value will be `null`. 511 * 512 * @see Builder#setCodeVerifier(String) 513 * @see Builder#setCodeVerifier(String, String, String) 514 * @see "Proof Key for Code Exchange by OAuth Public Clients (RFC 7636) 515 * <https://tools.ietf.org/html/rfc7636>" 516 */ 517 @Nullable 518 public final String codeVerifierChallengeMethod; 519 520 /** 521 * Instructs the authorization service on the mechanism to be used for returning 522 * response parameters from the authorization endpoint. This use of this parameter is 523 * _not recommended_ when the response mode that would be requested is the default mode 524 * specified for the response type. 525 * 526 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 527 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 528 */ 529 @Nullable 530 public final String responseMode; 531 532 /** 533 * Requests that specific Claims be returned. 534 * The value is a JSON object listing the requested Claims. 535 * 536 * @see "OpenID Connect Core 1.0, Section 5.5 537 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.5.5>" 538 */ 539 @Nullable 540 public final JSONObject claims; 541 542 /** 543 * End-User's preferred languages and scripts for Claims being returned, represented as a 544 * space-separated list of BCP47 [RFC5646] language tag values, ordered by preference. 545 * 546 * @see "OpenID Connect Core 1.0, Section 5.2 547 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.5.2>" 548 */ 549 @Nullable 550 public final String claimsLocales; 551 552 /** 553 * Additional parameters to be passed as part of the request. 554 * 555 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 3.1 556 * <https://tools.ietf.org/html/rfc6749#section-3.1>" 557 */ 558 @NonNull 559 public final Map<String, String> additionalParameters; 560 561 /** 562 * Creates instances of {@link AuthorizationRequest}. 563 */ 564 public static final class Builder { 565 566 // SuppressWarnings justification: static analysis incorrectly determines that this field 567 // is not initialized, as it is indirectly initialized by setConfiguration 568 @NonNull 569 @SuppressWarnings("NullableProblems") 570 private AuthorizationServiceConfiguration mConfiguration; 571 572 // SuppressWarnings justification: static analysis incorrectly determines that this field 573 // is not initialized, as it is indirectly initialized by setClientId 574 @NonNull 575 @SuppressWarnings("NullableProblems") 576 private String mClientId; 577 578 @Nullable 579 private String mDisplay; 580 581 @Nullable 582 private String mLoginHint; 583 584 @Nullable 585 private String mPrompt; 586 587 @Nullable 588 private String mUiLocales; 589 590 // SuppressWarnings justification: static analysis incorrectly determines that this field 591 // is not initialized, as it is indirectly initialized by setResponseType 592 @NonNull 593 @SuppressWarnings("NullableProblems") 594 private String mResponseType; 595 596 // SuppressWarnings justification: static analysis incorrectly determines that this field 597 // is not initialized, as it is indirectly initialized by setRedirectUri 598 @NonNull 599 @SuppressWarnings("NullableProblems") 600 private Uri mRedirectUri; 601 602 @Nullable 603 private String mScope; 604 605 @Nullable 606 private String mState; 607 608 @Nullable 609 private String mNonce; 610 611 @Nullable 612 private String mCodeVerifier; 613 614 @Nullable 615 private String mCodeVerifierChallenge; 616 617 @Nullable 618 private String mCodeVerifierChallengeMethod; 619 620 @Nullable 621 private String mResponseMode; 622 623 @Nullable 624 private JSONObject mClaims; 625 626 @Nullable 627 private String mClaimsLocales; 628 629 @NonNull 630 private Map<String, String> mAdditionalParameters = new HashMap<>(); 631 632 /** 633 * Creates an authorization request builder with the specified mandatory properties, 634 * and preset values for {@link AuthorizationRequest#state}, 635 * {@link AuthorizationRequest#nonce} and {@link AuthorizationRequest#codeVerifier}. 636 */ 637 public Builder( 638 @NonNull AuthorizationServiceConfiguration configuration, 639 @NonNull String clientId, 640 @NonNull String responseType, 641 @NonNull Uri redirectUri) { 642 setAuthorizationServiceConfiguration(configuration); 643 setClientId(clientId); 644 setResponseType(responseType); 645 setRedirectUri(redirectUri); 646 setState(AuthorizationManagementUtil.generateRandomState()); 647 setNonce(AuthorizationManagementUtil.generateRandomState()); 648 setCodeVerifier(CodeVerifierUtil.generateRandomCodeVerifier()); 649 } 650 651 /** 652 * Specifies the service configuration to be used in dispatching this request. 653 */ 654 public Builder setAuthorizationServiceConfiguration( 655 @NonNull AuthorizationServiceConfiguration configuration) { 656 mConfiguration = checkNotNull(configuration, 657 "configuration cannot be null"); 658 return this; 659 } 660 661 /** 662 * Specifies the client ID. Cannot be null or empty. 663 * 664 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 4 665 * <https://tools.ietf.org/html/rfc6749#section-4>" 666 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 4.1.1 667 * <https://tools.ietf.org/html/rfc6749#section-4.1.1>" 668 */ 669 @NonNull 670 public Builder setClientId(@NonNull String clientId) { 671 mClientId = checkNotEmpty(clientId, "client ID cannot be null or empty"); 672 return this; 673 } 674 675 /** 676 * Specifies the OpenID Connect 1.0 `display` parameter. 677 * 678 * @see Display 679 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 680 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 681 */ 682 public Builder setDisplay(@Nullable String display) { 683 mDisplay = checkNullOrNotEmpty(display, "display must be null or not empty"); 684 return this; 685 } 686 687 /** 688 * Specifies the OpenID Connect 1.0 `login_hint` parameter. 689 * 690 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 691 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 692 */ 693 public Builder setLoginHint(@Nullable String loginHint) { 694 mLoginHint = checkNullOrNotEmpty(loginHint, "login hint must be null or not empty"); 695 return this; 696 } 697 698 /** 699 * Specifies the encoded OpenID Connect 1.0 `prompt` parameter, which is a 700 * space-delimited set of case sensitive ASCII prompt values. Replaces any previously 701 * specified prompt values. 702 * 703 * @see Prompt 704 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 705 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 706 */ 707 @NonNull 708 public Builder setPrompt(@Nullable String prompt) { 709 mPrompt = checkNullOrNotEmpty(prompt, "prompt must be null or non-empty"); 710 return this; 711 } 712 713 /** 714 * Specifies the set of OpenID Connect 1.0 `prompt` parameter values, which are 715 * space-delimited, case sensitive ASCII prompt values. Replaces any previously 716 * specified prompt values. 717 * 718 * @see Prompt 719 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 720 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 721 */ 722 @NonNull 723 public Builder setPromptValues(@Nullable String... promptValues) { 724 if (promptValues == null) { 725 mPrompt = null; 726 return this; 727 } 728 729 return setPromptValues(Arrays.asList(promptValues)); 730 } 731 732 /** 733 * Specifies the set of OpenID Connect 1.0 `prompt` parameter values, which are 734 * space-delimited, case sensitive ASCII prompt values. Replaces any previously 735 * specified prompt values. 736 * 737 * @see Prompt 738 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 739 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 740 */ 741 @NonNull 742 public Builder setPromptValues(@Nullable Iterable<String> promptValues) { 743 mPrompt = AsciiStringListUtil.iterableToString(promptValues); 744 return this; 745 } 746 747 /** 748 * Specifies the OpenID Connect 1.0 `ui_locales` parameter, which is a space-separated list 749 * of BCP47 [RFC5646] language tag values, ordered by preference. It represents End-User's 750 * preferred languages and scripts for the user interface. Replaces any previously 751 * specified ui_locales values. 752 * 753 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 754 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 755 */ 756 public Builder setUiLocales(@Nullable String uiLocales) { 757 mUiLocales = checkNullOrNotEmpty(uiLocales, "uiLocales must be null or not empty"); 758 return this; 759 } 760 761 /** 762 * Specifies the OpenID Connect 1.0 `ui_locales` parameter, which is a space-separated list 763 * of BCP47 [RFC5646] language tag values, ordered by preference. It represents End-User's 764 * preferred languages and scripts for the user interface. Replaces any previously 765 * specified ui_locales values. 766 * 767 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 768 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 769 */ 770 @NonNull 771 public Builder setUiLocalesValues(@Nullable String... uiLocalesValues) { 772 if (uiLocalesValues == null) { 773 mUiLocales = null; 774 return this; 775 } 776 777 return setUiLocalesValues(Arrays.asList(uiLocalesValues)); 778 } 779 780 /** 781 * Specifies the OpenID Connect 1.0 `ui_locales` parameter, which is a space-separated list 782 * of BCP47 [RFC5646] language tag values, ordered by preference. It represents End-User's 783 * preferred languages and scripts for the user interface. Replaces any previously 784 * specified ui_locales values. 785 * 786 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 787 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 788 */ 789 @NonNull 790 public Builder setUiLocalesValues(@Nullable Iterable<String> uiLocalesValues) { 791 mUiLocales = AsciiStringListUtil.iterableToString(uiLocalesValues); 792 return this; 793 } 794 795 /** 796 * Specifies the expected response type. Cannot be null or empty. 797 * 798 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 2.2 799 * <https://tools.ietf.org/html/rfc6749#section-2.2>" 800 * @see "OpenID Connect Core 1.0, Section 3 801 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3>" 802 */ 803 @NonNull 804 public Builder setResponseType(@NonNull String responseType) { 805 mResponseType = checkNotEmpty(responseType, 806 "expected response type cannot be null or empty"); 807 return this; 808 } 809 810 /** 811 * Specifies the client's redirect URI. Cannot be null or empty. 812 * 813 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 3.1.2 814 * <https://tools.ietf.org/html/rfc6749#section-3.1.2>" 815 */ 816 @NonNull 817 public Builder setRedirectUri(@NonNull Uri redirectUri) { 818 mRedirectUri = checkNotNull(redirectUri, "redirect URI cannot be null or empty"); 819 return this; 820 } 821 822 /** 823 * Specifies the encoded scope string, which is a space-delimited set of 824 * case-sensitive scope identifiers. Replaces any previously specified scope. 825 * 826 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 3.3 827 * <https://tools.ietf.org/html/rfc6749#section-3.3>" 828 */ 829 @NonNull 830 public Builder setScope(@Nullable String scope) { 831 if (TextUtils.isEmpty(scope)) { 832 mScope = null; 833 } else { 834 setScopes(scope.split(" +")); 835 } 836 return this; 837 } 838 839 /** 840 * Specifies the set of case-sensitive scopes. Replaces any previously specified set of 841 * scopes. If no arguments are provided, the scope string will be set to `null`. 842 * Individual scope strings cannot be null or empty. 843 * 844 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 3.3 845 * <https://tools.ietf.org/html/rfc6749#section-3.3>" 846 */ 847 @NonNull 848 public Builder setScopes(String... scopes) { 849 if (scopes == null) { 850 scopes = new String[0]; 851 } 852 setScopes(Arrays.asList(scopes)); 853 return this; 854 } 855 856 /** 857 * Specifies the set of case-sensitive scopes. Replaces any previously specified set of 858 * scopes. If the iterable is empty, the scope string will be set to `null`. 859 * Individual scope strings cannot be null or empty. 860 * 861 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 3.3 862 * <https://tools.ietf.org/html/rfc6749#section-3.3>" 863 */ 864 @NonNull 865 public Builder setScopes(@Nullable Iterable<String> scopes) { 866 mScope = AsciiStringListUtil.iterableToString(scopes); 867 return this; 868 } 869 870 /** 871 * Specifies the opaque value used by the client to maintain state between the request and 872 * callback. If this value is not explicitly set, this library will automatically add state 873 * and perform appropriate validation of the state in the authorization response. It is 874 * recommended that the default implementation of this parameter be used wherever possible. 875 * Typically used to prevent CSRF attacks, as recommended in 876 * [RFC6819 Section 5.3.5](https://tools.ietf.org/html/rfc6819#section-5.3.5). 877 * 878 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 4.1.1 879 * <https://tools.ietf.org/html/rfc6749#section-4.1.1>" 880 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 5.3.5 881 * <https://tools.ietf.org/html/rfc6749#section-5.3.5>" 882 */ 883 @NonNull 884 public Builder setState(@Nullable String state) { 885 mState = checkNullOrNotEmpty(state, "state cannot be empty if defined"); 886 return this; 887 } 888 889 /** 890 * Specifies the String value used to associate a Client session with an ID Token, and to 891 * mitigate replay attacks. The value is passed through unmodified from the Authentication 892 * Request to the ID Token. If this value is not explicitly set, this library will 893 * automatically add nonce and perform appropriate validation of the ID Token. It is 894 * recommended that the default implementation of this parameter be used wherever possible. 895 * 896 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 897 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 898 */ 899 @NonNull 900 public Builder setNonce(@Nullable String nonce) { 901 mNonce = checkNullOrNotEmpty(nonce, "nonce cannot be empty if defined"); 902 return this; 903 } 904 905 /** 906 * Specifies the code verifier to use for this authorization request. The default challenge 907 * method (typically {@link #CODE_CHALLENGE_METHOD_S256}) implemented by 908 * {@link CodeVerifierUtil} will be used, and a challenge will be generated using this 909 * method. If the use of a code verifier is not desired, set the code verifier 910 * to `null`. 911 * 912 * @see "Proof Key for Code Exchange by OAuth Public Clients (RFC 7636), Section 4.3 913 * <https://tools.ietf.org/html/rfc7636#section-4.3>" 914 */ 915 @NonNull 916 public Builder setCodeVerifier(@Nullable String codeVerifier) { 917 if (codeVerifier != null) { 918 CodeVerifierUtil.checkCodeVerifier(codeVerifier); 919 mCodeVerifier = codeVerifier; 920 mCodeVerifierChallenge = CodeVerifierUtil.deriveCodeVerifierChallenge(codeVerifier); 921 mCodeVerifierChallengeMethod = CodeVerifierUtil.getCodeVerifierChallengeMethod(); 922 } else { 923 mCodeVerifier = null; 924 mCodeVerifierChallenge = null; 925 mCodeVerifierChallengeMethod = null; 926 } 927 928 return this; 929 } 930 931 /** 932 * Specifies the code verifier, challenge and method strings to use for this authorization 933 * request. If these values are not explicitly set, they will be automatically generated 934 * and used. It is recommended that this default behavior be used wherever possible. If 935 * a null code verifier is set (to indicate that a code verifier is not to be used), then 936 * the challenge and method must also be null. If a non-null code verifier is set, the 937 * code verifier challenge and method must also be set. 938 * 939 * @see "Proof Key for Code Exchange by OAuth Public Clients (RFC 7636), Section 4.3 940 * <https://tools.ietf.org/html/rfc7636#section-4.3>" 941 */ 942 @NonNull 943 public Builder setCodeVerifier( 944 @Nullable String codeVerifier, 945 @Nullable String codeVerifierChallenge, 946 @Nullable String codeVerifierChallengeMethod) { 947 if (codeVerifier != null) { 948 CodeVerifierUtil.checkCodeVerifier(codeVerifier); 949 checkNotEmpty(codeVerifierChallenge, 950 "code verifier challenge cannot be null or empty if verifier is set"); 951 checkNotEmpty(codeVerifierChallengeMethod, 952 "code verifier challenge method cannot be null or empty if verifier " 953 + "is set"); 954 } else { 955 checkArgument(codeVerifierChallenge == null, 956 "code verifier challenge must be null if verifier is null"); 957 checkArgument(codeVerifierChallengeMethod == null, 958 "code verifier challenge method must be null if verifier is null"); 959 } 960 961 mCodeVerifier = codeVerifier; 962 mCodeVerifierChallenge = codeVerifierChallenge; 963 mCodeVerifierChallengeMethod = codeVerifierChallengeMethod; 964 965 return this; 966 } 967 968 /** 969 * Specifies the response mode to be used for returning authorization response parameters 970 * from the authorization endpoint. 971 * 972 * @see "OpenID Connect Core 1.0, Section 3.1.2.1 973 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.3.1.2.1>" 974 * @see "OAuth 2.0 Multiple Response Type Encoding Practices, Section 2 975 * <http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#rfc.section.2>" 976 */ 977 @NonNull 978 public Builder setResponseMode(@Nullable String responseMode) { 979 checkNullOrNotEmpty(responseMode, "responseMode must not be empty"); 980 mResponseMode = responseMode; 981 return this; 982 } 983 984 /** 985 * Requests that specific Claims be returned. 986 * The value is a JSON object listing the requested Claims. 987 * 988 * @see "OpenID Connect Core 1.0, Section 5.5 989 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.5.5>" 990 */ 991 @NonNull 992 public Builder setClaims(@Nullable JSONObject claims) { 993 mClaims = claims; 994 return this; 995 } 996 997 /** 998 * End-User's preferred languages and scripts for Claims being returned, represented as a 999 * space-separated list of BCP47 [RFC5646] language tag values, ordered by preference. 1000 * 1001 * @see "OpenID Connect Core 1.0, Section 5.2 1002 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.5.2>" 1003 */ 1004 public Builder setClaimsLocales(@Nullable String claimsLocales) { 1005 mClaimsLocales = checkNullOrNotEmpty( 1006 claimsLocales, 1007 "claimsLocales must be null or not empty"); 1008 return this; 1009 } 1010 1011 /** 1012 * End-User's preferred languages and scripts for Claims being returned, represented as a 1013 * space-separated list of BCP47 [RFC5646] language tag values, ordered by preference. 1014 * 1015 * @see "OpenID Connect Core 1.0, Section 5.2 1016 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.5.2>" 1017 */ 1018 @NonNull 1019 public Builder setClaimsLocalesValues(@Nullable String... claimsLocalesValues) { 1020 if (claimsLocalesValues == null) { 1021 mClaimsLocales = null; 1022 return this; 1023 } 1024 1025 return setClaimsLocalesValues(Arrays.asList(claimsLocalesValues)); 1026 } 1027 1028 /** 1029 * End-User's preferred languages and scripts for Claims being returned, represented as a 1030 * space-separated list of BCP47 [RFC5646] language tag values, ordered by preference. 1031 * 1032 * @see "OpenID Connect Core 1.0, Section 5.2 1033 * <https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.5.2>" 1034 */ 1035 @NonNull 1036 public Builder setClaimsLocalesValues(@Nullable Iterable<String> claimsLocalesValues) { 1037 mClaimsLocales = AsciiStringListUtil.iterableToString(claimsLocalesValues); 1038 return this; 1039 } 1040 1041 /** 1042 * Specifies additional parameters. Replaces any previously provided set of parameters. 1043 * Parameter keys and values cannot be null or empty. 1044 * 1045 * @see "The OAuth 2.0 Authorization Framework (RFC 6749), Section 3.1 1046 * <https://tools.ietf.org/html/rfc6749#section-3.1>" 1047 */ 1048 @NonNull 1049 public Builder setAdditionalParameters(@Nullable Map<String, String> additionalParameters) { 1050 mAdditionalParameters = checkAdditionalParams(additionalParameters, BUILT_IN_PARAMS); 1051 return this; 1052 } 1053 1054 /** 1055 * Constructs the authorization request. At a minimum the following fields must have been 1056 * set: 1057 * 1058 * - The client ID 1059 * - The expected response type 1060 * - The redirect URI 1061 * 1062 * Failure to specify any of these parameters will result in a runtime exception. 1063 */ 1064 @NonNull 1065 public AuthorizationRequest build() { 1066 return new AuthorizationRequest( 1067 mConfiguration, 1068 mClientId, 1069 mResponseType, 1070 mRedirectUri, 1071 mDisplay, 1072 mLoginHint, 1073 mPrompt, 1074 mUiLocales, 1075 mScope, 1076 mState, 1077 mNonce, 1078 mCodeVerifier, 1079 mCodeVerifierChallenge, 1080 mCodeVerifierChallengeMethod, 1081 mResponseMode, 1082 mClaims, 1083 mClaimsLocales, 1084 Collections.unmodifiableMap(new HashMap<>(mAdditionalParameters))); 1085 } 1086 } 1087 1088 private AuthorizationRequest( 1089 @NonNull AuthorizationServiceConfiguration configuration, 1090 @NonNull String clientId, 1091 @NonNull String responseType, 1092 @NonNull Uri redirectUri, 1093 @Nullable String display, 1094 @Nullable String loginHint, 1095 @Nullable String prompt, 1096 @Nullable String uiLocales, 1097 @Nullable String scope, 1098 @Nullable String state, 1099 @Nullable String nonce, 1100 @Nullable String codeVerifier, 1101 @Nullable String codeVerifierChallenge, 1102 @Nullable String codeVerifierChallengeMethod, 1103 @Nullable String responseMode, 1104 @Nullable JSONObject claims, 1105 @Nullable String claimsLocales, 1106 @NonNull Map<String, String> additionalParameters) { 1107 // mandatory fields 1108 this.configuration = configuration; 1109 this.clientId = clientId; 1110 this.responseType = responseType; 1111 this.redirectUri = redirectUri; 1112 this.additionalParameters = additionalParameters; 1113 1114 // optional fields 1115 this.display = display; 1116 this.loginHint = loginHint; 1117 this.prompt = prompt; 1118 this.uiLocales = uiLocales; 1119 this.scope = scope; 1120 this.state = state; 1121 this.nonce = nonce; 1122 this.codeVerifier = codeVerifier; 1123 this.codeVerifierChallenge = codeVerifierChallenge; 1124 this.codeVerifierChallengeMethod = codeVerifierChallengeMethod; 1125 this.responseMode = responseMode; 1126 this.claims = claims; 1127 this.claimsLocales = claimsLocales; 1128 } 1129 1130 /** 1131 * Derives the set of scopes from the consolidated, space-delimited scopes in the 1132 * {@link #scope} field. If no scopes were specified for this request, the method will 1133 * return `null`. 1134 */ 1135 @Nullable 1136 public Set<String> getScopeSet() { 1137 return AsciiStringListUtil.stringToSet(scope); 1138 } 1139 1140 /** 1141 * Derives the set of prompt values from the consolidated, space-delimited prompt values in 1142 * the {@link #prompt} field. If no prompt values were specified for this request, the method 1143 * will return `null`. 1144 */ 1145 public Set<String> getPromptValues() { 1146 return AsciiStringListUtil.stringToSet(prompt); 1147 } 1148 1149 /** 1150 * Derives the set of ui_locales values from the consolidated, space-separated list of 1151 * BCP47 [RFC5646] language tag values in the {@link #uiLocales} field. If no ui_locales values 1152 * were specified for this request, the method will return `null`. 1153 */ 1154 public Set<String> getUiLocales() { 1155 return AsciiStringListUtil.stringToSet(uiLocales); 1156 } 1157 1158 @Override 1159 @Nullable 1160 public String getState() { 1161 return state; 1162 } 1163 1164 /** 1165 * Derives the set of claims_locales values from the consolidated, space-separated list of 1166 * BCP47 [RFC5646] language tag values in the {@link #claimsLocales} field. If no claims_locales 1167 * values were specified for this request, the method will return `null`. 1168 */ 1169 public Set<String> getClaimsLocales() { 1170 return AsciiStringListUtil.stringToSet(claimsLocales); 1171 } 1172 1173 /** 1174 * Produces a request URI, that can be used to dispatch the authorization request. 1175 */ 1176 @Override 1177 @NonNull 1178 public Uri toUri() { 1179 Uri.Builder uriBuilder = configuration.authorizationEndpoint.buildUpon() 1180 .appendQueryParameter(PARAM_REDIRECT_URI, redirectUri.toString()) 1181 .appendQueryParameter(PARAM_CLIENT_ID, clientId) 1182 .appendQueryParameter(PARAM_RESPONSE_TYPE, responseType); 1183 1184 UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_DISPLAY, display); 1185 UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_LOGIN_HINT, loginHint); 1186 UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_PROMPT, prompt); 1187 UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_UI_LOCALES, uiLocales); 1188 UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_STATE, state); 1189 UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_NONCE, nonce); 1190 UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_SCOPE, scope); 1191 UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_RESPONSE_MODE, responseMode); 1192 1193 if (codeVerifier != null) { 1194 uriBuilder.appendQueryParameter(PARAM_CODE_CHALLENGE, codeVerifierChallenge) 1195 .appendQueryParameter(PARAM_CODE_CHALLENGE_METHOD, codeVerifierChallengeMethod); 1196 } 1197 1198 UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_CLAIMS, claims); 1199 UriUtil.appendQueryParameterIfNotNull(uriBuilder, PARAM_CLAIMS_LOCALES, claimsLocales); 1200 1201 for (Entry<String, String> entry : additionalParameters.entrySet()) { 1202 uriBuilder.appendQueryParameter(entry.getKey(), entry.getValue()); 1203 } 1204 1205 return uriBuilder.build(); 1206 } 1207 1208 /** 1209 * Produces a JSON representation of the authorization request for persistent storage or local 1210 * transmission (e.g. between activities). 1211 */ 1212 @Override 1213 @NonNull 1214 public JSONObject jsonSerialize() { 1215 JSONObject json = new JSONObject(); 1216 JsonUtil.put(json, KEY_CONFIGURATION, configuration.toJson()); 1217 JsonUtil.put(json, KEY_CLIENT_ID, clientId); 1218 JsonUtil.put(json, KEY_RESPONSE_TYPE, responseType); 1219 JsonUtil.put(json, KEY_REDIRECT_URI, redirectUri.toString()); 1220 JsonUtil.putIfNotNull(json, KEY_DISPLAY, display); 1221 JsonUtil.putIfNotNull(json, KEY_LOGIN_HINT, loginHint); 1222 JsonUtil.putIfNotNull(json, KEY_SCOPE, scope); 1223 JsonUtil.putIfNotNull(json, KEY_PROMPT, prompt); 1224 JsonUtil.putIfNotNull(json, KEY_UI_LOCALES, uiLocales); 1225 JsonUtil.putIfNotNull(json, KEY_STATE, state); 1226 JsonUtil.putIfNotNull(json, KEY_NONCE, nonce); 1227 JsonUtil.putIfNotNull(json, KEY_CODE_VERIFIER, codeVerifier); 1228 JsonUtil.putIfNotNull(json, KEY_CODE_VERIFIER_CHALLENGE, codeVerifierChallenge); 1229 JsonUtil.putIfNotNull(json, KEY_CODE_VERIFIER_CHALLENGE_METHOD, 1230 codeVerifierChallengeMethod); 1231 JsonUtil.putIfNotNull(json, KEY_RESPONSE_MODE, responseMode); 1232 JsonUtil.putIfNotNull(json, KEY_CLAIMS, claims); 1233 JsonUtil.putIfNotNull(json, KEY_CLAIMS_LOCALES, claimsLocales); 1234 JsonUtil.put(json, KEY_ADDITIONAL_PARAMETERS, 1235 JsonUtil.mapToJsonObject(additionalParameters)); 1236 return json; 1237 } 1238 1239 /** 1240 * Produces a JSON string representation of the request for persistent storage or 1241 * local transmission (e.g. between activities). This method is just a convenience wrapper 1242 * for {@link #jsonSerialize()}, converting the JSON object to its string form. 1243 */ 1244 @Override 1245 public String jsonSerializeString() { 1246 return jsonSerialize().toString(); 1247 } 1248 1249 /** 1250 * Reads an authorization request from a JSON string representation produced by 1251 * {@link #jsonSerialize()}. 1252 * @throws JSONException if the provided JSON does not match the expected structure. 1253 */ 1254 @NonNull 1255 public static AuthorizationRequest jsonDeserialize(@NonNull JSONObject json) 1256 throws JSONException { 1257 checkNotNull(json, "json cannot be null"); 1258 return new AuthorizationRequest( 1259 AuthorizationServiceConfiguration.fromJson(json.getJSONObject(KEY_CONFIGURATION)), 1260 JsonUtil.getString(json, KEY_CLIENT_ID), 1261 JsonUtil.getString(json, KEY_RESPONSE_TYPE), 1262 JsonUtil.getUri(json, KEY_REDIRECT_URI), 1263 JsonUtil.getStringIfDefined(json, KEY_DISPLAY), 1264 JsonUtil.getStringIfDefined(json, KEY_LOGIN_HINT), 1265 JsonUtil.getStringIfDefined(json, KEY_PROMPT), 1266 JsonUtil.getStringIfDefined(json, KEY_UI_LOCALES), 1267 JsonUtil.getStringIfDefined(json, KEY_SCOPE), 1268 JsonUtil.getStringIfDefined(json, KEY_STATE), 1269 JsonUtil.getStringIfDefined(json, KEY_NONCE), 1270 JsonUtil.getStringIfDefined(json, KEY_CODE_VERIFIER), 1271 JsonUtil.getStringIfDefined(json, KEY_CODE_VERIFIER_CHALLENGE), 1272 JsonUtil.getStringIfDefined(json, KEY_CODE_VERIFIER_CHALLENGE_METHOD), 1273 JsonUtil.getStringIfDefined(json, KEY_RESPONSE_MODE), 1274 JsonUtil.getJsonObjectIfDefined(json, KEY_CLAIMS), 1275 JsonUtil.getStringIfDefined(json, KEY_CLAIMS_LOCALES), 1276 JsonUtil.getStringMap(json, KEY_ADDITIONAL_PARAMETERS)); 1277 } 1278 1279 /** 1280 * Reads an authorization request from a JSON string representation produced by 1281 * {@link #jsonSerializeString()}. This method is just a convenience wrapper for 1282 * {@link #jsonDeserialize(JSONObject)}, converting the JSON string to its JSON object form. 1283 * @throws JSONException if the provided JSON does not match the expected structure. 1284 */ 1285 @NonNull 1286 public static AuthorizationRequest jsonDeserialize(@NonNull String jsonStr) 1287 throws JSONException { 1288 checkNotNull(jsonStr, "json string cannot be null"); 1289 return jsonDeserialize(new JSONObject(jsonStr)); 1290 } 1291}