(
authorizationServerUrl: string | URL,
{
metadata,
clientInformation,
redirectUrl,
scope,
state,
resource
}: {
metadata?: AuthorizationServerMetadata;
clientInformation: OAuthClientInformationMixed;
redirectUrl: string | URL;
scope?: string;
state?: string;
resource?: URL;
}
)
| 1112 | * Begins the authorization flow with the given server, by generating a PKCE challenge and constructing the authorization URL. |
| 1113 | */ |
| 1114 | export async function startAuthorization( |
| 1115 | authorizationServerUrl: string | URL, |
| 1116 | { |
| 1117 | metadata, |
| 1118 | clientInformation, |
| 1119 | redirectUrl, |
| 1120 | scope, |
| 1121 | state, |
| 1122 | resource |
| 1123 | }: { |
| 1124 | metadata?: AuthorizationServerMetadata; |
| 1125 | clientInformation: OAuthClientInformationMixed; |
| 1126 | redirectUrl: string | URL; |
| 1127 | scope?: string; |
| 1128 | state?: string; |
| 1129 | resource?: URL; |
| 1130 | } |
| 1131 | ): Promise<{ authorizationUrl: URL; codeVerifier: string }> { |
| 1132 | let authorizationUrl: URL; |
| 1133 | if (metadata) { |
| 1134 | authorizationUrl = new URL(metadata.authorization_endpoint); |
| 1135 | |
| 1136 | if (!metadata.response_types_supported.includes(AUTHORIZATION_CODE_RESPONSE_TYPE)) { |
| 1137 | throw new Error(`Incompatible auth server: does not support response type ${AUTHORIZATION_CODE_RESPONSE_TYPE}`); |
| 1138 | } |
| 1139 | |
| 1140 | if ( |
| 1141 | metadata.code_challenge_methods_supported && |
| 1142 | !metadata.code_challenge_methods_supported.includes(AUTHORIZATION_CODE_CHALLENGE_METHOD) |
| 1143 | ) { |
| 1144 | throw new Error(`Incompatible auth server: does not support code challenge method ${AUTHORIZATION_CODE_CHALLENGE_METHOD}`); |
| 1145 | } |
| 1146 | } else { |
| 1147 | authorizationUrl = new URL('/authorize', authorizationServerUrl); |
| 1148 | } |
| 1149 | |
| 1150 | // Generate PKCE challenge |
| 1151 | const challenge = await pkceChallenge(); |
| 1152 | const codeVerifier = challenge.code_verifier; |
| 1153 | const codeChallenge = challenge.code_challenge; |
| 1154 | |
| 1155 | authorizationUrl.searchParams.set('response_type', AUTHORIZATION_CODE_RESPONSE_TYPE); |
| 1156 | authorizationUrl.searchParams.set('client_id', clientInformation.client_id); |
| 1157 | authorizationUrl.searchParams.set('code_challenge', codeChallenge); |
| 1158 | authorizationUrl.searchParams.set('code_challenge_method', AUTHORIZATION_CODE_CHALLENGE_METHOD); |
| 1159 | authorizationUrl.searchParams.set('redirect_uri', String(redirectUrl)); |
| 1160 | |
| 1161 | if (state) { |
| 1162 | authorizationUrl.searchParams.set('state', state); |
| 1163 | } |
| 1164 | |
| 1165 | if (scope) { |
| 1166 | authorizationUrl.searchParams.set('scope', scope); |
| 1167 | } |
| 1168 | |
| 1169 | if (scope?.includes('offline_access')) { |
| 1170 | // if the request includes the OIDC-only "offline_access" scope, |
| 1171 | // we need to set the prompt to "consent" to ensure the user is prompted to grant offline access |
no test coverage detected
searching dependent graphs…