@maronn-openid-connect/core 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +145 -0
- package/dist/access-token-issuer.d.ts +14 -0
- package/dist/access-token-issuer.d.ts.map +1 -0
- package/dist/access-token-issuer.js +32 -0
- package/dist/access-token-issuer.js.map +1 -0
- package/dist/access-token.d.ts +19 -0
- package/dist/access-token.d.ts.map +1 -0
- package/dist/access-token.js +46 -0
- package/dist/access-token.js.map +1 -0
- package/dist/auth-transaction.d.ts +86 -0
- package/dist/auth-transaction.d.ts.map +1 -0
- package/dist/auth-transaction.js +187 -0
- package/dist/auth-transaction.js.map +1 -0
- package/dist/authorization-code-grant.d.ts +15 -0
- package/dist/authorization-code-grant.d.ts.map +1 -0
- package/dist/authorization-code-grant.js +109 -0
- package/dist/authorization-code-grant.js.map +1 -0
- package/dist/authorization-code.d.ts +28 -0
- package/dist/authorization-code.d.ts.map +1 -0
- package/dist/authorization-code.js +41 -0
- package/dist/authorization-code.js.map +1 -0
- package/dist/authorization-request.d.ts +128 -0
- package/dist/authorization-request.d.ts.map +1 -0
- package/dist/authorization-request.js +457 -0
- package/dist/authorization-request.js.map +1 -0
- package/dist/client-auth.d.ts +16 -0
- package/dist/client-auth.d.ts.map +1 -0
- package/dist/client-auth.js +116 -0
- package/dist/client-auth.js.map +1 -0
- package/dist/crypto-utils.d.ts +18 -0
- package/dist/crypto-utils.d.ts.map +1 -0
- package/dist/crypto-utils.js +197 -0
- package/dist/crypto-utils.js.map +1 -0
- package/dist/discovery.d.ts +56 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +133 -0
- package/dist/discovery.js.map +1 -0
- package/dist/error-utils.d.ts +2 -0
- package/dist/error-utils.d.ts.map +1 -0
- package/dist/error-utils.js +13 -0
- package/dist/error-utils.js.map +1 -0
- package/dist/id-token.d.ts +39 -0
- package/dist/id-token.d.ts.map +1 -0
- package/dist/id-token.js +193 -0
- package/dist/id-token.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/introspection.d.ts +66 -0
- package/dist/introspection.d.ts.map +1 -0
- package/dist/introspection.js +139 -0
- package/dist/introspection.js.map +1 -0
- package/dist/jwks.d.ts +29 -0
- package/dist/jwks.d.ts.map +1 -0
- package/dist/jwks.js +36 -0
- package/dist/jwks.js.map +1 -0
- package/dist/loopback.d.ts +2 -0
- package/dist/loopback.d.ts.map +1 -0
- package/dist/loopback.js +6 -0
- package/dist/loopback.js.map +1 -0
- package/dist/refresh-token-grant.d.ts +14 -0
- package/dist/refresh-token-grant.d.ts.map +1 -0
- package/dist/refresh-token-grant.js +87 -0
- package/dist/refresh-token-grant.js.map +1 -0
- package/dist/request-object.d.ts +11 -0
- package/dist/request-object.d.ts.map +1 -0
- package/dist/request-object.js +92 -0
- package/dist/request-object.js.map +1 -0
- package/dist/revocation.d.ts +51 -0
- package/dist/revocation.d.ts.map +1 -0
- package/dist/revocation.js +93 -0
- package/dist/revocation.js.map +1 -0
- package/dist/signing-key.d.ts +21 -0
- package/dist/signing-key.d.ts.map +1 -0
- package/dist/signing-key.js +99 -0
- package/dist/signing-key.js.map +1 -0
- package/dist/token-error.d.ts +16 -0
- package/dist/token-error.d.ts.map +1 -0
- package/dist/token-error.js +31 -0
- package/dist/token-error.js.map +1 -0
- package/dist/token-request.d.ts +111 -0
- package/dist/token-request.d.ts.map +1 -0
- package/dist/token-request.js +44 -0
- package/dist/token-request.js.map +1 -0
- package/dist/token-response.d.ts +111 -0
- package/dist/token-response.d.ts.map +1 -0
- package/dist/token-response.js +173 -0
- package/dist/token-response.js.map +1 -0
- package/dist/userinfo.d.ts +98 -0
- package/dist/userinfo.d.ts.map +1 -0
- package/dist/userinfo.js +188 -0
- package/dist/userinfo.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
import { sanitizeErrorDescription } from './error-utils.js';
|
|
2
|
+
import { isLoopbackHostname } from './loopback.js';
|
|
3
|
+
import { parseRequestObject, RequestObjectError } from './request-object.js';
|
|
4
|
+
export const DEFAULT_REQUEST_OBJECT_SIGNING_ALGS = ['RS256'];
|
|
5
|
+
export var AuthorizationErrorCode;
|
|
6
|
+
(function (AuthorizationErrorCode) {
|
|
7
|
+
AuthorizationErrorCode["InvalidRequest"] = "invalid_request";
|
|
8
|
+
AuthorizationErrorCode["UnauthorizedClient"] = "unauthorized_client";
|
|
9
|
+
AuthorizationErrorCode["AccessDenied"] = "access_denied";
|
|
10
|
+
AuthorizationErrorCode["UnsupportedResponseType"] = "unsupported_response_type";
|
|
11
|
+
AuthorizationErrorCode["InvalidScope"] = "invalid_scope";
|
|
12
|
+
AuthorizationErrorCode["ServerError"] = "server_error";
|
|
13
|
+
AuthorizationErrorCode["TemporarilyUnavailable"] = "temporarily_unavailable";
|
|
14
|
+
AuthorizationErrorCode["InteractionRequired"] = "interaction_required";
|
|
15
|
+
AuthorizationErrorCode["LoginRequired"] = "login_required";
|
|
16
|
+
AuthorizationErrorCode["AccountSelectionRequired"] = "account_selection_required";
|
|
17
|
+
AuthorizationErrorCode["ConsentRequired"] = "consent_required";
|
|
18
|
+
AuthorizationErrorCode["RequestNotSupported"] = "request_not_supported";
|
|
19
|
+
AuthorizationErrorCode["RequestUriNotSupported"] = "request_uri_not_supported";
|
|
20
|
+
AuthorizationErrorCode["RegistrationNotSupported"] = "registration_not_supported";
|
|
21
|
+
})(AuthorizationErrorCode || (AuthorizationErrorCode = {}));
|
|
22
|
+
export const defaultIsOfflineAccessGranted = (_request, { promptValues }) => promptValues.includes('consent');
|
|
23
|
+
export const DEFAULT_MAX_CLAIMS_PARAMETER_LENGTH = 16384;
|
|
24
|
+
export class AuthorizationError extends Error {
|
|
25
|
+
error;
|
|
26
|
+
errorDescription;
|
|
27
|
+
redirectUri;
|
|
28
|
+
state;
|
|
29
|
+
constructor(error, errorDescription, redirectUri, state) {
|
|
30
|
+
const sanitized = sanitizeErrorDescription(errorDescription);
|
|
31
|
+
super(sanitized);
|
|
32
|
+
this.name = 'AuthorizationError';
|
|
33
|
+
this.error = error;
|
|
34
|
+
this.errorDescription = sanitized;
|
|
35
|
+
this.redirectUri = redirectUri;
|
|
36
|
+
this.state = state;
|
|
37
|
+
}
|
|
38
|
+
get redirectable() {
|
|
39
|
+
return this.redirectUri !== undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const VALID_PROMPT_VALUES = ['none', 'login', 'consent', 'select_account'];
|
|
43
|
+
const VALID_DISPLAY_VALUES = ['page', 'popup', 'touch', 'wap'];
|
|
44
|
+
const VALID_CODE_CHALLENGE_METHODS = ['S256'];
|
|
45
|
+
const CODE_CHALLENGE_S256_LENGTH = 43;
|
|
46
|
+
const CODE_CHALLENGE_S256_PATTERN = /^[A-Za-z0-9\-_]+$/;
|
|
47
|
+
function matchRedirectUri(requestUri, registeredUris, clientType) {
|
|
48
|
+
if (registeredUris.includes(requestUri)) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
if (clientType !== 'public') {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const requestUrl = new URL(requestUri);
|
|
56
|
+
if (isLoopbackHostname(requestUrl.hostname)) {
|
|
57
|
+
return registeredUris.some((registeredUri) => {
|
|
58
|
+
try {
|
|
59
|
+
const registeredUrl = new URL(registeredUri);
|
|
60
|
+
return (isLoopbackHostname(registeredUrl.hostname) &&
|
|
61
|
+
requestUrl.protocol === registeredUrl.protocol &&
|
|
62
|
+
requestUrl.hostname === registeredUrl.hostname &&
|
|
63
|
+
requestUrl.pathname === registeredUrl.pathname &&
|
|
64
|
+
requestUrl.search === registeredUrl.search);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
const DANGEROUS_SCHEMES = new Set([
|
|
77
|
+
'javascript:',
|
|
78
|
+
'data:',
|
|
79
|
+
'file:',
|
|
80
|
+
'vbscript:',
|
|
81
|
+
'blob:',
|
|
82
|
+
]);
|
|
83
|
+
export function validateRegisteredRedirectUris(registeredUris) {
|
|
84
|
+
for (const uri of registeredUris) {
|
|
85
|
+
if (uri.includes('#')) {
|
|
86
|
+
throw new AuthorizationError(AuthorizationErrorCode.ServerError, `Registered redirect_uri must not contain fragment: ${uri}`);
|
|
87
|
+
}
|
|
88
|
+
const colonIndex = uri.indexOf(':');
|
|
89
|
+
if (colonIndex === -1) {
|
|
90
|
+
throw new AuthorizationError(AuthorizationErrorCode.ServerError, `Registered redirect_uri must include a scheme: ${uri}`);
|
|
91
|
+
}
|
|
92
|
+
const scheme = uri.slice(0, colonIndex + 1).toLowerCase();
|
|
93
|
+
if (DANGEROUS_SCHEMES.has(scheme)) {
|
|
94
|
+
throw new AuthorizationError(AuthorizationErrorCode.ServerError, `Registered redirect_uri uses a dangerous scheme: ${scheme} (${uri})`);
|
|
95
|
+
}
|
|
96
|
+
if (scheme === 'http:') {
|
|
97
|
+
let parsed;
|
|
98
|
+
try {
|
|
99
|
+
parsed = new URL(uri);
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
throw new AuthorizationError(AuthorizationErrorCode.ServerError, `Registered redirect_uri is not a valid URL: ${uri}`);
|
|
103
|
+
}
|
|
104
|
+
if (!isLoopbackHostname(parsed.hostname)) {
|
|
105
|
+
throw new AuthorizationError(AuthorizationErrorCode.ServerError, `Registered redirect_uri must use https:// or loopback http:// — got ${uri}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function resolveRedirectUri(requestRedirectUri, registeredUris, clientType) {
|
|
111
|
+
if (requestRedirectUri !== undefined) {
|
|
112
|
+
if (requestRedirectUri.includes('#')) {
|
|
113
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, 'redirect_uri must not contain fragment');
|
|
114
|
+
}
|
|
115
|
+
if (!matchRedirectUri(requestRedirectUri, registeredUris, clientType)) {
|
|
116
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, 'redirect_uri not registered');
|
|
117
|
+
}
|
|
118
|
+
return requestRedirectUri;
|
|
119
|
+
}
|
|
120
|
+
if (registeredUris.length === 1) {
|
|
121
|
+
return registeredUris[0];
|
|
122
|
+
}
|
|
123
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, 'redirect_uri is required when multiple redirect URIs are registered');
|
|
124
|
+
}
|
|
125
|
+
export function resolveAuthorizationRedirectUri(effectiveParams, client) {
|
|
126
|
+
return resolveRedirectUri(effectiveParams.redirect_uri, client.redirectUris, client.clientType);
|
|
127
|
+
}
|
|
128
|
+
export function validatePromptParameter(effectiveParams, redirectUri, state) {
|
|
129
|
+
if (effectiveParams.prompt === undefined) {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
return validatePrompt(effectiveParams.prompt, redirectUri, state);
|
|
133
|
+
}
|
|
134
|
+
function validatePrompt(promptValue, redirectUri, state) {
|
|
135
|
+
const values = promptValue.split(' ').filter((v) => v.length > 0);
|
|
136
|
+
for (const value of values) {
|
|
137
|
+
if (!VALID_PROMPT_VALUES.includes(value)) {
|
|
138
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, `Invalid prompt value: ${value}`, redirectUri, state);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (values.includes('none') && values.length > 1) {
|
|
142
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, 'prompt value "none" must not be combined with other values', redirectUri, state);
|
|
143
|
+
}
|
|
144
|
+
return values;
|
|
145
|
+
}
|
|
146
|
+
function validateMaxAge(maxAgeValue, redirectUri, state) {
|
|
147
|
+
const num = Number(maxAgeValue);
|
|
148
|
+
if (!Number.isFinite(num) || !Number.isInteger(num) || num < 0) {
|
|
149
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, 'max_age must be a non-negative integer', redirectUri, state);
|
|
150
|
+
}
|
|
151
|
+
return num;
|
|
152
|
+
}
|
|
153
|
+
function validateDefaultMaxAge(defaultMaxAge) {
|
|
154
|
+
if (!Number.isFinite(defaultMaxAge) ||
|
|
155
|
+
!Number.isInteger(defaultMaxAge) ||
|
|
156
|
+
defaultMaxAge < 0) {
|
|
157
|
+
throw new AuthorizationError(AuthorizationErrorCode.ServerError, 'Registered default_max_age must be a non-negative integer');
|
|
158
|
+
}
|
|
159
|
+
return defaultMaxAge;
|
|
160
|
+
}
|
|
161
|
+
export function resolveMaxAge(effectiveParams, client, redirectUri, state) {
|
|
162
|
+
if (effectiveParams.max_age !== undefined) {
|
|
163
|
+
return validateMaxAge(effectiveParams.max_age, redirectUri, state);
|
|
164
|
+
}
|
|
165
|
+
if (client.defaultMaxAge !== undefined) {
|
|
166
|
+
return validateDefaultMaxAge(client.defaultMaxAge);
|
|
167
|
+
}
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
function validateCodeChallenge(codeChallenge, codeChallengeMethod, redirectUri, state) {
|
|
171
|
+
if (!codeChallenge) {
|
|
172
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, 'Missing required parameter: code_challenge', redirectUri, state);
|
|
173
|
+
}
|
|
174
|
+
if (!codeChallengeMethod) {
|
|
175
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, 'Missing required parameter: code_challenge_method', redirectUri, state);
|
|
176
|
+
}
|
|
177
|
+
if (!VALID_CODE_CHALLENGE_METHODS.includes(codeChallengeMethod)) {
|
|
178
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, `Unsupported code_challenge_method: ${codeChallengeMethod}`, redirectUri, state);
|
|
179
|
+
}
|
|
180
|
+
if (codeChallenge.length !== CODE_CHALLENGE_S256_LENGTH) {
|
|
181
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, `code_challenge must be a ${CODE_CHALLENGE_S256_LENGTH}-character base64url-encoded SHA-256 hash for S256`, redirectUri, state);
|
|
182
|
+
}
|
|
183
|
+
if (!CODE_CHALLENGE_S256_PATTERN.test(codeChallenge)) {
|
|
184
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, 'code_challenge contains invalid characters (must be base64url: [A-Za-z0-9-_], 43 chars)', redirectUri, state);
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
codeChallenge,
|
|
188
|
+
codeChallengeMethod: codeChallengeMethod,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
export function validateAuthorizationCodePkce(effectiveParams, client, redirectUri, state, options = {}) {
|
|
192
|
+
const codeChallenge = effectiveParams.code_challenge;
|
|
193
|
+
const codeChallengeMethod = effectiveParams.code_challenge_method;
|
|
194
|
+
const pkceOmitted = codeChallenge === undefined && codeChallengeMethod === undefined;
|
|
195
|
+
if (pkceOmitted &&
|
|
196
|
+
options.allowNonPkceAuthorizationCodeFlow === true &&
|
|
197
|
+
client.clientType === 'confidential') {
|
|
198
|
+
return {};
|
|
199
|
+
}
|
|
200
|
+
return validateCodeChallenge(codeChallenge, codeChallengeMethod, redirectUri, state);
|
|
201
|
+
}
|
|
202
|
+
export async function resolveClientForAuthorization(params, clientResolver) {
|
|
203
|
+
const clientId = params.client_id;
|
|
204
|
+
if (!clientId) {
|
|
205
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, 'Missing required parameter: client_id');
|
|
206
|
+
}
|
|
207
|
+
const client = await clientResolver.findClient(clientId);
|
|
208
|
+
if (!client) {
|
|
209
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, 'Unknown client_id');
|
|
210
|
+
}
|
|
211
|
+
if (client.clientId !== clientId) {
|
|
212
|
+
throw new AuthorizationError(AuthorizationErrorCode.ServerError, `ClientResolver returned mismatched clientId: expected "${clientId}", got "${client.clientId}". ` +
|
|
213
|
+
'Ensure findClient returns data for the queried client_id. ' +
|
|
214
|
+
'clientId mismatch detected.');
|
|
215
|
+
}
|
|
216
|
+
return client;
|
|
217
|
+
}
|
|
218
|
+
export async function resolveRequestObjectParams(params, client, options = {}) {
|
|
219
|
+
if (params.request === undefined) {
|
|
220
|
+
return { effectiveParams: { ...params } };
|
|
221
|
+
}
|
|
222
|
+
let requestObjectClaims;
|
|
223
|
+
try {
|
|
224
|
+
requestObjectClaims = await parseRequestObject(params.request, {
|
|
225
|
+
jwks: client.jwks,
|
|
226
|
+
supportedSigningAlgs: options.supportedSigningAlgs ?? [
|
|
227
|
+
...DEFAULT_REQUEST_OBJECT_SIGNING_ALGS,
|
|
228
|
+
],
|
|
229
|
+
allowUnsigned: options.allowUnsigned ?? false,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
catch (e) {
|
|
233
|
+
if (e instanceof RequestObjectError) {
|
|
234
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, e.message);
|
|
235
|
+
}
|
|
236
|
+
throw e;
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
effectiveParams: mergeRequestObjectParams(params, requestObjectClaims),
|
|
240
|
+
requestObjectClaims,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
export function rejectUnsupportedRequestParams(params, redirectUri, state, options = {}) {
|
|
244
|
+
if (params.request !== undefined &&
|
|
245
|
+
options.requestParameterSupported === false) {
|
|
246
|
+
throw new AuthorizationError(AuthorizationErrorCode.RequestNotSupported, 'request parameter (Request Object) is not supported', redirectUri, state);
|
|
247
|
+
}
|
|
248
|
+
if (params.request_uri !== undefined) {
|
|
249
|
+
throw new AuthorizationError(AuthorizationErrorCode.RequestUriNotSupported, 'request_uri parameter (Request Object by reference) is not supported', redirectUri, state);
|
|
250
|
+
}
|
|
251
|
+
if (params.registration !== undefined) {
|
|
252
|
+
throw new AuthorizationError(AuthorizationErrorCode.RegistrationNotSupported, 'registration parameter is not supported', redirectUri, state);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
export function validateRequestObjectConsistency(params, requestObjectClaims, redirectUri, state) {
|
|
256
|
+
if (requestObjectClaims === undefined) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const roResponseType = typeof requestObjectClaims['response_type'] === 'string'
|
|
260
|
+
? requestObjectClaims['response_type']
|
|
261
|
+
: undefined;
|
|
262
|
+
if (roResponseType !== undefined && roResponseType !== params.response_type) {
|
|
263
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, 'request object response_type does not match the request', redirectUri, state);
|
|
264
|
+
}
|
|
265
|
+
const roClientId = typeof requestObjectClaims['client_id'] === 'string'
|
|
266
|
+
? requestObjectClaims['client_id']
|
|
267
|
+
: undefined;
|
|
268
|
+
if (roClientId !== undefined && roClientId !== params.client_id) {
|
|
269
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, 'request object client_id does not match the request', redirectUri, state);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
export function validateResponseType(params, client, redirectUri, state) {
|
|
273
|
+
const responseType = params.response_type;
|
|
274
|
+
if (!responseType) {
|
|
275
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, 'Missing required parameter: response_type', redirectUri, state);
|
|
276
|
+
}
|
|
277
|
+
if (responseType !== 'code') {
|
|
278
|
+
throw new AuthorizationError(AuthorizationErrorCode.UnsupportedResponseType, `Unsupported response_type: ${responseType}`, redirectUri, state);
|
|
279
|
+
}
|
|
280
|
+
const allowedResponseTypes = client.responseTypes ?? ['code'];
|
|
281
|
+
if (!allowedResponseTypes.includes(responseType)) {
|
|
282
|
+
throw new AuthorizationError(AuthorizationErrorCode.UnauthorizedClient, `Client is not authorized to use response_type: ${responseType}`, redirectUri, state);
|
|
283
|
+
}
|
|
284
|
+
return responseType;
|
|
285
|
+
}
|
|
286
|
+
export function validateAuthorizationScope(queryParams, effectiveParams, redirectUri, state) {
|
|
287
|
+
const queryScopeValue = queryParams.scope;
|
|
288
|
+
if (!queryScopeValue) {
|
|
289
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, 'Missing required parameter: scope', redirectUri, state);
|
|
290
|
+
}
|
|
291
|
+
const scopeValue = effectiveParams.scope ?? queryScopeValue;
|
|
292
|
+
const scope = [...new Set(scopeValue.split(' ').filter((s) => s.length > 0))];
|
|
293
|
+
if (!scope.includes('openid')) {
|
|
294
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidScope, 'scope must include openid', redirectUri, state);
|
|
295
|
+
}
|
|
296
|
+
return scope;
|
|
297
|
+
}
|
|
298
|
+
export async function applyOfflineAccessPolicy(scope, effectiveParams, promptValues, isOfflineAccessGranted = defaultIsOfflineAccessGranted) {
|
|
299
|
+
if (!scope.includes('offline_access')) {
|
|
300
|
+
return scope;
|
|
301
|
+
}
|
|
302
|
+
const granted = await isOfflineAccessGranted(effectiveParams, {
|
|
303
|
+
promptValues: promptValues ?? [],
|
|
304
|
+
});
|
|
305
|
+
if (granted) {
|
|
306
|
+
return scope;
|
|
307
|
+
}
|
|
308
|
+
return scope.filter((s) => s !== 'offline_access');
|
|
309
|
+
}
|
|
310
|
+
export function validateDisplayParameter(effectiveParams, redirectUri, state) {
|
|
311
|
+
const display = effectiveParams.display;
|
|
312
|
+
if (display !== undefined &&
|
|
313
|
+
!VALID_DISPLAY_VALUES.includes(display)) {
|
|
314
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, `Unsupported display value: ${display}`, redirectUri, state);
|
|
315
|
+
}
|
|
316
|
+
return display;
|
|
317
|
+
}
|
|
318
|
+
export function parseAudienceParameter(effectiveParams) {
|
|
319
|
+
const audienceValue = effectiveParams.audience;
|
|
320
|
+
if (audienceValue === undefined) {
|
|
321
|
+
return undefined;
|
|
322
|
+
}
|
|
323
|
+
return audienceValue.split(' ').filter((a) => a.length > 0);
|
|
324
|
+
}
|
|
325
|
+
export async function validateAuthorizationRequest(params, clientResolver, options = {}) {
|
|
326
|
+
const client = await resolveClientForAuthorization(params, clientResolver);
|
|
327
|
+
validateRegisteredRedirectUris(client.redirectUris);
|
|
328
|
+
const requestParameterSupported = options.requestObject?.supported ?? true;
|
|
329
|
+
const { effectiveParams: effective, requestObjectClaims } = requestParameterSupported
|
|
330
|
+
? await resolveRequestObjectParams(params, client, {
|
|
331
|
+
supportedSigningAlgs: options.requestObject?.supportedSigningAlgs,
|
|
332
|
+
allowUnsigned: options.requestObject?.allowUnsigned,
|
|
333
|
+
})
|
|
334
|
+
: { effectiveParams: { ...params }, requestObjectClaims: undefined };
|
|
335
|
+
const redirectUri = resolveAuthorizationRedirectUri(effective, client);
|
|
336
|
+
const state = effective.state;
|
|
337
|
+
rejectUnsupportedRequestParams(params, redirectUri, state, {
|
|
338
|
+
requestParameterSupported,
|
|
339
|
+
});
|
|
340
|
+
validateRequestObjectConsistency(params, requestObjectClaims, redirectUri, state);
|
|
341
|
+
const responseType = validateResponseType(params, client, redirectUri, state);
|
|
342
|
+
let scope = validateAuthorizationScope(params, effective, redirectUri, state);
|
|
343
|
+
const pkce = validateAuthorizationCodePkce(effective, client, redirectUri, state, {
|
|
344
|
+
allowNonPkceAuthorizationCodeFlow: options.allowNonPkceAuthorizationCodeFlow,
|
|
345
|
+
});
|
|
346
|
+
const prompt = validatePromptParameter(effective, redirectUri, state);
|
|
347
|
+
scope = await applyOfflineAccessPolicy(scope, effective, prompt, options.isOfflineAccessGranted);
|
|
348
|
+
const display = validateDisplayParameter(effective, redirectUri, state);
|
|
349
|
+
const maxAge = resolveMaxAge(effective, client, redirectUri, state);
|
|
350
|
+
const audience = parseAudienceParameter(effective);
|
|
351
|
+
const claims = parseClaimsRequestParameter(effective, redirectUri, state, options.maxClaimsParameterLength);
|
|
352
|
+
return {
|
|
353
|
+
responseType,
|
|
354
|
+
clientId: client.clientId,
|
|
355
|
+
redirectUri,
|
|
356
|
+
redirectUriExplicit: effective.redirect_uri !== undefined,
|
|
357
|
+
scope,
|
|
358
|
+
codeChallenge: pkce.codeChallenge,
|
|
359
|
+
codeChallengeMethod: pkce.codeChallengeMethod,
|
|
360
|
+
state,
|
|
361
|
+
nonce: effective.nonce,
|
|
362
|
+
prompt,
|
|
363
|
+
display,
|
|
364
|
+
maxAge,
|
|
365
|
+
uiLocales: effective.ui_locales,
|
|
366
|
+
claimsLocales: effective.claims_locales,
|
|
367
|
+
acrValues: effective.acr_values,
|
|
368
|
+
loginHint: effective.login_hint,
|
|
369
|
+
idTokenHint: effective.id_token_hint,
|
|
370
|
+
audience,
|
|
371
|
+
claims,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
const REQUEST_OBJECT_OVERRIDE_KEYS = [
|
|
375
|
+
'redirect_uri',
|
|
376
|
+
'scope',
|
|
377
|
+
'state',
|
|
378
|
+
'nonce',
|
|
379
|
+
'prompt',
|
|
380
|
+
'display',
|
|
381
|
+
'max_age',
|
|
382
|
+
'ui_locales',
|
|
383
|
+
'claims_locales',
|
|
384
|
+
'acr_values',
|
|
385
|
+
'login_hint',
|
|
386
|
+
'id_token_hint',
|
|
387
|
+
'audience',
|
|
388
|
+
'code_challenge',
|
|
389
|
+
'code_challenge_method',
|
|
390
|
+
];
|
|
391
|
+
function mergeRequestObjectParams(params, roClaims) {
|
|
392
|
+
const overrides = {};
|
|
393
|
+
for (const key of REQUEST_OBJECT_OVERRIDE_KEYS) {
|
|
394
|
+
const value = roClaims[key];
|
|
395
|
+
if (value === undefined)
|
|
396
|
+
continue;
|
|
397
|
+
if (typeof value === 'string') {
|
|
398
|
+
overrides[key] = value;
|
|
399
|
+
}
|
|
400
|
+
else if (typeof value === 'number' || typeof value === 'boolean') {
|
|
401
|
+
overrides[key] = String(value);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
const claimsValue = roClaims['claims'];
|
|
405
|
+
if (typeof claimsValue === 'string') {
|
|
406
|
+
overrides['claims'] = claimsValue;
|
|
407
|
+
}
|
|
408
|
+
else if (typeof claimsValue === 'object' &&
|
|
409
|
+
claimsValue !== null &&
|
|
410
|
+
!Array.isArray(claimsValue)) {
|
|
411
|
+
overrides['claims'] = JSON.stringify(claimsValue);
|
|
412
|
+
}
|
|
413
|
+
return { ...params, ...overrides };
|
|
414
|
+
}
|
|
415
|
+
export function parseClaimsRequestParameter(effectiveParams, redirectUri, state, maxLength = DEFAULT_MAX_CLAIMS_PARAMETER_LENGTH) {
|
|
416
|
+
const raw = effectiveParams.claims;
|
|
417
|
+
if (raw === undefined)
|
|
418
|
+
return undefined;
|
|
419
|
+
if (raw.length > maxLength) {
|
|
420
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, 'claims parameter exceeds the maximum allowed length', redirectUri, state);
|
|
421
|
+
}
|
|
422
|
+
let parsed;
|
|
423
|
+
try {
|
|
424
|
+
parsed = JSON.parse(raw);
|
|
425
|
+
}
|
|
426
|
+
catch {
|
|
427
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, 'claims parameter must be a JSON object', redirectUri, state);
|
|
428
|
+
}
|
|
429
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
430
|
+
throw new AuthorizationError(AuthorizationErrorCode.InvalidRequest, 'claims parameter must be a JSON object', redirectUri, state);
|
|
431
|
+
}
|
|
432
|
+
const result = {};
|
|
433
|
+
const obj = parsed;
|
|
434
|
+
const userinfo = sanitizeClaimsMember(obj['userinfo']);
|
|
435
|
+
if (userinfo)
|
|
436
|
+
result.userinfo = userinfo;
|
|
437
|
+
const idToken = sanitizeClaimsMember(obj['id_token']);
|
|
438
|
+
if (idToken)
|
|
439
|
+
result.id_token = idToken;
|
|
440
|
+
return result;
|
|
441
|
+
}
|
|
442
|
+
function sanitizeClaimsMember(value) {
|
|
443
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
444
|
+
return undefined;
|
|
445
|
+
}
|
|
446
|
+
const result = {};
|
|
447
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
448
|
+
if (entry === null) {
|
|
449
|
+
result[key] = null;
|
|
450
|
+
}
|
|
451
|
+
else if (typeof entry === 'object' && !Array.isArray(entry)) {
|
|
452
|
+
result[key] = entry;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return result;
|
|
456
|
+
}
|
|
457
|
+
//# sourceMappingURL=authorization-request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorization-request.js","sourceRoot":"","sources":["../src/authorization-request.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TokenClientInfo, TokenClientResolver } from './token-request.js';
|
|
2
|
+
export interface ClientAuthContext {
|
|
3
|
+
params: Record<string, string | undefined>;
|
|
4
|
+
authorizationHeader: string;
|
|
5
|
+
clientResolver: TokenClientResolver;
|
|
6
|
+
}
|
|
7
|
+
export interface PresentedClientCredentials {
|
|
8
|
+
clientId: string;
|
|
9
|
+
clientSecret?: string;
|
|
10
|
+
method: 'client_secret_basic' | 'client_secret_post' | 'none';
|
|
11
|
+
}
|
|
12
|
+
export declare function extractClientCredentials(context: Pick<ClientAuthContext, 'params' | 'authorizationHeader'>): PresentedClientCredentials;
|
|
13
|
+
export declare function validateClientAuthMethod(client: TokenClientInfo, presented: PresentedClientCredentials): void;
|
|
14
|
+
export declare function verifyClientSecret(client: TokenClientInfo, clientSecret: string | undefined): Promise<void>;
|
|
15
|
+
export declare function authenticateClient(context: ClientAuthContext): Promise<string>;
|
|
16
|
+
//# sourceMappingURL=client-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-auth.d.ts","sourceRoot":"","sources":["../src/client-auth.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAK/E,MAAM,WAAW,iBAAiB;IAEhC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAE3C,mBAAmB,EAAE,MAAM,CAAC;IAE5B,cAAc,EAAE,mBAAmB,CAAC;CACrC;AA6ED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IAEjB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,MAAM,EAAE,qBAAqB,GAAG,oBAAoB,GAAG,MAAM,CAAC;CAC/D;AAeD,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,IAAI,CAAC,iBAAiB,EAAE,QAAQ,GAAG,qBAAqB,CAAC,GACjE,0BAA0B,CAgE5B;AAcD,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,0BAA0B,GACpC,IAAI,CAiCN;AAUD,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,eAAe,EACvB,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,OAAO,CAAC,IAAI,CAAC,CAef;AAqBD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,MAAM,CAAC,CAUjB"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { timingSafeEqual } from './crypto-utils.js';
|
|
2
|
+
import { resolveAuthenticatedTokenClient, TokenError, TokenErrorCode, } from './token-request.js';
|
|
3
|
+
function formUrlDecode(value) {
|
|
4
|
+
return decodeURIComponent(value.replace(/\+/g, '%20'));
|
|
5
|
+
}
|
|
6
|
+
function matchAuthScheme(authHeader, scheme) {
|
|
7
|
+
const spaceIndex = authHeader.indexOf(' ');
|
|
8
|
+
if (spaceIndex === -1) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
const headerScheme = authHeader.slice(0, spaceIndex).toLowerCase();
|
|
12
|
+
if (headerScheme !== scheme.toLowerCase()) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
return authHeader.slice(spaceIndex + 1);
|
|
16
|
+
}
|
|
17
|
+
function hasAuthScheme(authHeader, scheme) {
|
|
18
|
+
return matchAuthScheme(authHeader, scheme) !== null;
|
|
19
|
+
}
|
|
20
|
+
function parseBasicAuth(authHeader) {
|
|
21
|
+
const base64Credentials = matchAuthScheme(authHeader, 'Basic');
|
|
22
|
+
if (base64Credentials === null) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
let decoded;
|
|
26
|
+
try {
|
|
27
|
+
const binary = atob(base64Credentials);
|
|
28
|
+
const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
29
|
+
decoded = new TextDecoder().decode(bytes);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const separatorIndex = decoded.indexOf(':');
|
|
35
|
+
if (separatorIndex === -1) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
return {
|
|
40
|
+
clientId: formUrlDecode(decoded.slice(0, separatorIndex)),
|
|
41
|
+
clientSecret: formUrlDecode(decoded.slice(separatorIndex + 1)),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export function extractClientCredentials(context) {
|
|
49
|
+
const { params, authorizationHeader } = context;
|
|
50
|
+
const hasBasicHeader = hasAuthScheme(authorizationHeader, 'Basic');
|
|
51
|
+
const hasPostCredential = params.client_id !== undefined || params.client_secret !== undefined;
|
|
52
|
+
const hasPostSecret = params.client_secret !== undefined;
|
|
53
|
+
if (hasBasicHeader && hasPostSecret) {
|
|
54
|
+
throw new TokenError(TokenErrorCode.InvalidRequest, 'Multiple client authentication methods provided. Use either Authorization header or request body, not both.');
|
|
55
|
+
}
|
|
56
|
+
let clientId;
|
|
57
|
+
let clientSecret;
|
|
58
|
+
if (hasBasicHeader) {
|
|
59
|
+
const basic = parseBasicAuth(authorizationHeader);
|
|
60
|
+
if (!basic) {
|
|
61
|
+
throw new TokenError(TokenErrorCode.InvalidClient, 'Invalid Authorization header format');
|
|
62
|
+
}
|
|
63
|
+
if (params.client_id !== undefined &&
|
|
64
|
+
params.client_id !== basic.clientId) {
|
|
65
|
+
throw new TokenError(TokenErrorCode.InvalidRequest, 'client_id in request body does not match the Authorization header');
|
|
66
|
+
}
|
|
67
|
+
clientId = basic.clientId;
|
|
68
|
+
clientSecret = basic.clientSecret;
|
|
69
|
+
}
|
|
70
|
+
else if (hasPostCredential) {
|
|
71
|
+
clientId = params.client_id;
|
|
72
|
+
clientSecret = params.client_secret;
|
|
73
|
+
}
|
|
74
|
+
if (!clientId) {
|
|
75
|
+
throw new TokenError(TokenErrorCode.InvalidClient, 'Client authentication required');
|
|
76
|
+
}
|
|
77
|
+
const method = hasBasicHeader
|
|
78
|
+
? 'client_secret_basic'
|
|
79
|
+
: clientSecret !== undefined
|
|
80
|
+
? 'client_secret_post'
|
|
81
|
+
: 'none';
|
|
82
|
+
return { clientId, clientSecret, method };
|
|
83
|
+
}
|
|
84
|
+
export function validateClientAuthMethod(client, presented) {
|
|
85
|
+
const registeredMethod = client.tokenEndpointAuthMethod ?? 'client_secret_basic';
|
|
86
|
+
if (registeredMethod === 'none') {
|
|
87
|
+
if (presented.method !== 'none') {
|
|
88
|
+
throw new TokenError(TokenErrorCode.InvalidClient, 'Client authentication method does not match the registered token_endpoint_auth_method');
|
|
89
|
+
}
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (!presented.clientSecret) {
|
|
93
|
+
throw new TokenError(TokenErrorCode.InvalidClient, 'Client authentication required');
|
|
94
|
+
}
|
|
95
|
+
if (presented.method !== registeredMethod) {
|
|
96
|
+
throw new TokenError(TokenErrorCode.InvalidClient, 'Client authentication method does not match the registered token_endpoint_auth_method');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
export async function verifyClientSecret(client, clientSecret) {
|
|
100
|
+
const registeredMethod = client.tokenEndpointAuthMethod ?? 'client_secret_basic';
|
|
101
|
+
if (registeredMethod === 'none')
|
|
102
|
+
return;
|
|
103
|
+
const secretMatches = await timingSafeEqual(client.clientSecret ?? '', clientSecret ?? '');
|
|
104
|
+
if (!secretMatches) {
|
|
105
|
+
throw new TokenError(TokenErrorCode.InvalidClient, 'Client authentication failed');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
export async function authenticateClient(context) {
|
|
109
|
+
const { params, authorizationHeader, clientResolver } = context;
|
|
110
|
+
const presented = extractClientCredentials({ params, authorizationHeader });
|
|
111
|
+
const client = await resolveAuthenticatedTokenClient(presented.clientId, clientResolver);
|
|
112
|
+
validateClientAuthMethod(client, presented);
|
|
113
|
+
await verifyClientSecret(client, presented.clientSecret);
|
|
114
|
+
return presented.clientId;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=client-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-auth.js","sourceRoot":"","sources":["../src/client-auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { webcrypto } from 'node:crypto';
|
|
2
|
+
export declare function sign(data: string, privateKey: CryptoKey): Promise<string>;
|
|
3
|
+
export declare function verify(data: string, signature: string, publicKey: CryptoKey): Promise<boolean>;
|
|
4
|
+
export declare function generateRandomString(byteLength: number): string;
|
|
5
|
+
export declare function timingSafeEqual(a: string, b: string): Promise<boolean>;
|
|
6
|
+
export declare function sha256(data: string): Promise<string>;
|
|
7
|
+
export declare function arrayBufferToBase64Url(buffer: ArrayBuffer): string;
|
|
8
|
+
export declare function base64UrlToArrayBuffer(base64url: string): ArrayBuffer;
|
|
9
|
+
export declare function base64UrlToArrayBufferStrict(base64url: string): ArrayBuffer;
|
|
10
|
+
export declare function stringToArrayBuffer(str: string): ArrayBuffer;
|
|
11
|
+
export declare function rsaModulusBitLength(jwkN: string): number;
|
|
12
|
+
export declare function importPrivateKeyFromJwk(jwkString: string, algorithm?: webcrypto.RsaHashedImportParams | webcrypto.EcKeyImportParams, keyUsages?: webcrypto.KeyUsage[]): Promise<CryptoKey>;
|
|
13
|
+
export declare function importPublicKeyFromJwk(jwkString: string, algorithm?: webcrypto.RsaHashedImportParams | webcrypto.EcKeyImportParams, keyUsages?: webcrypto.KeyUsage[]): Promise<CryptoKey>;
|
|
14
|
+
export declare function extractAlgorithmParams(key: CryptoKey): webcrypto.RsaHashedImportParams | webcrypto.EcKeyImportParams;
|
|
15
|
+
export declare function extractAlgorithmParamsFromJwk(jwk: webcrypto.JsonWebKey): webcrypto.RsaHashedImportParams | webcrypto.EcKeyImportParams;
|
|
16
|
+
export declare function jwaToHashName(alg: string): 'SHA-256' | 'SHA-384' | 'SHA-512';
|
|
17
|
+
export declare function getJwaAlgorithm(key: CryptoKey): string;
|
|
18
|
+
//# sourceMappingURL=crypto-utils.d.ts.map
|