@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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +145 -0
  3. package/dist/access-token-issuer.d.ts +14 -0
  4. package/dist/access-token-issuer.d.ts.map +1 -0
  5. package/dist/access-token-issuer.js +32 -0
  6. package/dist/access-token-issuer.js.map +1 -0
  7. package/dist/access-token.d.ts +19 -0
  8. package/dist/access-token.d.ts.map +1 -0
  9. package/dist/access-token.js +46 -0
  10. package/dist/access-token.js.map +1 -0
  11. package/dist/auth-transaction.d.ts +86 -0
  12. package/dist/auth-transaction.d.ts.map +1 -0
  13. package/dist/auth-transaction.js +187 -0
  14. package/dist/auth-transaction.js.map +1 -0
  15. package/dist/authorization-code-grant.d.ts +15 -0
  16. package/dist/authorization-code-grant.d.ts.map +1 -0
  17. package/dist/authorization-code-grant.js +109 -0
  18. package/dist/authorization-code-grant.js.map +1 -0
  19. package/dist/authorization-code.d.ts +28 -0
  20. package/dist/authorization-code.d.ts.map +1 -0
  21. package/dist/authorization-code.js +41 -0
  22. package/dist/authorization-code.js.map +1 -0
  23. package/dist/authorization-request.d.ts +128 -0
  24. package/dist/authorization-request.d.ts.map +1 -0
  25. package/dist/authorization-request.js +457 -0
  26. package/dist/authorization-request.js.map +1 -0
  27. package/dist/client-auth.d.ts +16 -0
  28. package/dist/client-auth.d.ts.map +1 -0
  29. package/dist/client-auth.js +116 -0
  30. package/dist/client-auth.js.map +1 -0
  31. package/dist/crypto-utils.d.ts +18 -0
  32. package/dist/crypto-utils.d.ts.map +1 -0
  33. package/dist/crypto-utils.js +197 -0
  34. package/dist/crypto-utils.js.map +1 -0
  35. package/dist/discovery.d.ts +56 -0
  36. package/dist/discovery.d.ts.map +1 -0
  37. package/dist/discovery.js +133 -0
  38. package/dist/discovery.js.map +1 -0
  39. package/dist/error-utils.d.ts +2 -0
  40. package/dist/error-utils.d.ts.map +1 -0
  41. package/dist/error-utils.js +13 -0
  42. package/dist/error-utils.js.map +1 -0
  43. package/dist/id-token.d.ts +39 -0
  44. package/dist/id-token.d.ts.map +1 -0
  45. package/dist/id-token.js +193 -0
  46. package/dist/id-token.js.map +1 -0
  47. package/dist/index.d.ts +34 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +19 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/introspection.d.ts +66 -0
  52. package/dist/introspection.d.ts.map +1 -0
  53. package/dist/introspection.js +139 -0
  54. package/dist/introspection.js.map +1 -0
  55. package/dist/jwks.d.ts +29 -0
  56. package/dist/jwks.d.ts.map +1 -0
  57. package/dist/jwks.js +36 -0
  58. package/dist/jwks.js.map +1 -0
  59. package/dist/loopback.d.ts +2 -0
  60. package/dist/loopback.d.ts.map +1 -0
  61. package/dist/loopback.js +6 -0
  62. package/dist/loopback.js.map +1 -0
  63. package/dist/refresh-token-grant.d.ts +14 -0
  64. package/dist/refresh-token-grant.d.ts.map +1 -0
  65. package/dist/refresh-token-grant.js +87 -0
  66. package/dist/refresh-token-grant.js.map +1 -0
  67. package/dist/request-object.d.ts +11 -0
  68. package/dist/request-object.d.ts.map +1 -0
  69. package/dist/request-object.js +92 -0
  70. package/dist/request-object.js.map +1 -0
  71. package/dist/revocation.d.ts +51 -0
  72. package/dist/revocation.d.ts.map +1 -0
  73. package/dist/revocation.js +93 -0
  74. package/dist/revocation.js.map +1 -0
  75. package/dist/signing-key.d.ts +21 -0
  76. package/dist/signing-key.d.ts.map +1 -0
  77. package/dist/signing-key.js +99 -0
  78. package/dist/signing-key.js.map +1 -0
  79. package/dist/token-error.d.ts +16 -0
  80. package/dist/token-error.d.ts.map +1 -0
  81. package/dist/token-error.js +31 -0
  82. package/dist/token-error.js.map +1 -0
  83. package/dist/token-request.d.ts +111 -0
  84. package/dist/token-request.d.ts.map +1 -0
  85. package/dist/token-request.js +44 -0
  86. package/dist/token-request.js.map +1 -0
  87. package/dist/token-response.d.ts +111 -0
  88. package/dist/token-response.d.ts.map +1 -0
  89. package/dist/token-response.js +173 -0
  90. package/dist/token-response.js.map +1 -0
  91. package/dist/userinfo.d.ts +98 -0
  92. package/dist/userinfo.d.ts.map +1 -0
  93. package/dist/userinfo.js +188 -0
  94. package/dist/userinfo.js.map +1 -0
  95. package/package.json +52 -0
@@ -0,0 +1,87 @@
1
+ import { TokenError, TokenErrorCode } from './token-error.js';
2
+ export async function resolveRefreshToken(params, refreshTokenResolver) {
3
+ const refreshToken = params.refresh_token;
4
+ if (!refreshToken) {
5
+ throw new TokenError(TokenErrorCode.InvalidRequest, 'Missing required parameter: refresh_token');
6
+ }
7
+ if (!refreshTokenResolver) {
8
+ throw new TokenError(TokenErrorCode.InvalidRequest, 'Refresh token resolver not provided');
9
+ }
10
+ const refreshTokenInfo = await refreshTokenResolver.resolve(refreshToken);
11
+ if (!refreshTokenInfo) {
12
+ throw new TokenError(TokenErrorCode.InvalidGrant, 'Refresh token not found');
13
+ }
14
+ return { refreshToken, refreshTokenInfo };
15
+ }
16
+ export async function validateRefreshTokenUnused(refreshTokenInfo, refreshTokenResolver) {
17
+ if (!refreshTokenInfo.used) {
18
+ return;
19
+ }
20
+ if (refreshTokenResolver.revokeTokensByGrantId) {
21
+ await refreshTokenResolver.revokeTokensByGrantId(refreshTokenInfo.grantId);
22
+ }
23
+ throw new TokenError(TokenErrorCode.InvalidGrant, 'Refresh token has already been used');
24
+ }
25
+ export function validateRefreshTokenClient(refreshTokenInfo, authenticatedClientId) {
26
+ if (refreshTokenInfo.clientId !== authenticatedClientId) {
27
+ throw new TokenError(TokenErrorCode.InvalidGrant, 'Refresh token was issued to a different client');
28
+ }
29
+ }
30
+ export function validateRefreshTokenExpiration(refreshTokenInfo, currentTime = Math.floor(Date.now() / 1000)) {
31
+ if (refreshTokenInfo.expiresAt <= currentTime) {
32
+ throw new TokenError(TokenErrorCode.InvalidGrant, 'Refresh token has expired');
33
+ }
34
+ }
35
+ export function validateRefreshTokenIdleTimeout(refreshTokenInfo, idleTimeoutSeconds, currentTime = Math.floor(Date.now() / 1000)) {
36
+ if (idleTimeoutSeconds !== undefined &&
37
+ idleTimeoutSeconds > 0 &&
38
+ refreshTokenInfo.lastUsedAt !== undefined &&
39
+ currentTime - refreshTokenInfo.lastUsedAt > idleTimeoutSeconds) {
40
+ throw new TokenError(TokenErrorCode.InvalidGrant, 'Refresh token expired due to inactivity');
41
+ }
42
+ }
43
+ export function validateRefreshTokenScope(requestedScope, originalScope) {
44
+ if (requestedScope === undefined) {
45
+ return originalScope;
46
+ }
47
+ const requestedScopes = requestedScope.split(' ').filter((scope) => scope.length > 0);
48
+ if (requestedScopes.length === 0) {
49
+ throw new TokenError(TokenErrorCode.InvalidScope, 'Requested scope must not be empty');
50
+ }
51
+ const uniqueRequestedScopes = [...new Set(requestedScopes)];
52
+ const originalScopeSet = new Set(originalScope);
53
+ const invalidScopes = uniqueRequestedScopes.filter((scope) => !originalScopeSet.has(scope));
54
+ if (invalidScopes.length > 0) {
55
+ throw new TokenError(TokenErrorCode.InvalidScope, `Requested scope exceeds original grant: ${invalidScopes.join(' ')}`);
56
+ }
57
+ return uniqueRequestedScopes;
58
+ }
59
+ export function buildValidatedRefreshTokenRequest(refreshTokenInfo, authenticatedClientId, effectiveScope) {
60
+ return {
61
+ grantType: 'refresh_token',
62
+ clientId: authenticatedClientId,
63
+ subject: refreshTokenInfo.subject,
64
+ scope: effectiveScope,
65
+ grantId: refreshTokenInfo.grantId,
66
+ audience: refreshTokenInfo.audience,
67
+ authTime: refreshTokenInfo.authTime,
68
+ nonce: refreshTokenInfo.nonce,
69
+ acr: refreshTokenInfo.acr,
70
+ amr: refreshTokenInfo.amr,
71
+ azp: refreshTokenInfo.azp,
72
+ originalIssuedAt: refreshTokenInfo.originalIssuedAt,
73
+ hadOfflineAccess: refreshTokenInfo.scope.includes('offline_access'),
74
+ };
75
+ }
76
+ export async function validateRefreshTokenGrant(context) {
77
+ const { params, authenticatedClientId, refreshTokenResolver, refreshTokenIdleTimeoutSeconds, } = context;
78
+ const { refreshTokenInfo } = await resolveRefreshToken(params, refreshTokenResolver);
79
+ const resolver = refreshTokenResolver;
80
+ await validateRefreshTokenUnused(refreshTokenInfo, resolver);
81
+ validateRefreshTokenClient(refreshTokenInfo, authenticatedClientId);
82
+ validateRefreshTokenExpiration(refreshTokenInfo);
83
+ validateRefreshTokenIdleTimeout(refreshTokenInfo, refreshTokenIdleTimeoutSeconds);
84
+ const effectiveScope = validateRefreshTokenScope(params.scope, refreshTokenInfo.scope);
85
+ return buildValidatedRefreshTokenRequest(refreshTokenInfo, authenticatedClientId, effectiveScope);
86
+ }
87
+ //# sourceMappingURL=refresh-token-grant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh-token-grant.js","sourceRoot":"","sources":["../src/refresh-token-grant.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { JwkSet } from './jwks.js';
2
+ export declare class RequestObjectError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ export interface ParseRequestObjectOptions {
6
+ jwks?: JwkSet;
7
+ supportedSigningAlgs: string[];
8
+ allowUnsigned: boolean;
9
+ }
10
+ export declare function parseRequestObject(request: string, options: ParseRequestObjectOptions): Promise<Record<string, unknown>>;
11
+ //# sourceMappingURL=request-object.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-object.d.ts","sourceRoot":"","sources":["../src/request-object.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAO,MAAM,EAAE,MAAM,WAAW,CAAC;AAQ7C,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAKD,MAAM,WAAW,yBAAyB;IAKxC,IAAI,CAAC,EAAE,MAAM,CAAC;IAId,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAO/B,aAAa,EAAE,OAAO,CAAC;CACxB;AAkBD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA8FlC"}
@@ -0,0 +1,92 @@
1
+ import { verify, base64UrlToArrayBuffer, extractAlgorithmParamsFromJwk } from './crypto-utils.js';
2
+ export class RequestObjectError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = 'RequestObjectError';
6
+ }
7
+ }
8
+ function decodeJwtSegment(segment) {
9
+ const json = new TextDecoder().decode(base64UrlToArrayBuffer(segment));
10
+ return JSON.parse(json);
11
+ }
12
+ export async function parseRequestObject(request, options) {
13
+ if (typeof request !== 'string' || request.length === 0) {
14
+ throw new RequestObjectError('request object is empty');
15
+ }
16
+ const parts = request.split('.');
17
+ if (parts.length !== 3) {
18
+ throw new RequestObjectError('request object is not a JWS compact serialization');
19
+ }
20
+ const [headerB64, payloadB64, signatureB64] = parts;
21
+ let header;
22
+ try {
23
+ const decoded = decodeJwtSegment(headerB64);
24
+ if (typeof decoded !== 'object' || decoded === null || Array.isArray(decoded)) {
25
+ throw new Error('header is not a JSON object');
26
+ }
27
+ header = decoded;
28
+ }
29
+ catch {
30
+ throw new RequestObjectError('request object header is not valid base64url JSON');
31
+ }
32
+ let payload;
33
+ try {
34
+ payload = decodeJwtSegment(payloadB64);
35
+ }
36
+ catch {
37
+ throw new RequestObjectError('request object payload is not valid base64url JSON');
38
+ }
39
+ if (typeof payload !== 'object' || payload === null || Array.isArray(payload)) {
40
+ throw new RequestObjectError('request object payload is not a JSON object');
41
+ }
42
+ const alg = typeof header['alg'] === 'string' ? header['alg'] : undefined;
43
+ if (!alg) {
44
+ throw new RequestObjectError('request object header is missing alg');
45
+ }
46
+ if (alg === 'none') {
47
+ if (!options.allowUnsigned) {
48
+ throw new RequestObjectError('unsigned request object (alg=none) is not supported');
49
+ }
50
+ if (signatureB64 !== '') {
51
+ throw new RequestObjectError('unsigned request object must not carry a signature');
52
+ }
53
+ return payload;
54
+ }
55
+ if (!options.supportedSigningAlgs.includes(alg)) {
56
+ throw new RequestObjectError(`unsupported request object signing alg: ${alg}`);
57
+ }
58
+ const jwks = options.jwks;
59
+ if (!jwks || jwks.keys.length === 0) {
60
+ throw new RequestObjectError('no JWKS registered to verify the request object signature');
61
+ }
62
+ const kid = typeof header['kid'] === 'string' ? header['kid'] : undefined;
63
+ const candidates = kid
64
+ ? jwks.keys.filter((k) => k.kid === kid)
65
+ : jwks.keys.slice();
66
+ if (candidates.length === 0) {
67
+ throw new RequestObjectError('no JWK matched the request object header (kid)');
68
+ }
69
+ const signingInput = `${headerB64}.${payloadB64}`;
70
+ for (const jwk of candidates) {
71
+ if (jwk.alg && jwk.alg !== alg) {
72
+ continue;
73
+ }
74
+ let publicKey;
75
+ try {
76
+ const algParams = extractAlgorithmParamsFromJwk(jwk);
77
+ publicKey = await crypto.subtle.importKey('jwk', jwk, algParams, false, ['verify']);
78
+ }
79
+ catch {
80
+ continue;
81
+ }
82
+ try {
83
+ if (await verify(signingInput, signatureB64, publicKey)) {
84
+ return payload;
85
+ }
86
+ }
87
+ catch {
88
+ }
89
+ }
90
+ throw new RequestObjectError('request object signature verification failed');
91
+ }
92
+ //# sourceMappingURL=request-object.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-object.js","sourceRoot":"","sources":["../src/request-object.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import type { AccessTokenInfo } from './userinfo.js';
2
+ import type { RefreshTokenInfo } from './token-request.js';
3
+ export declare enum RevocationErrorCode {
4
+ InvalidRequest = "invalid_request",
5
+ InvalidClient = "invalid_client",
6
+ InvalidGrant = "invalid_grant"
7
+ }
8
+ export declare class RevocationError extends Error {
9
+ readonly error: RevocationErrorCode;
10
+ readonly errorDescription: string;
11
+ constructor(error: RevocationErrorCode, errorDescription: string);
12
+ get statusCode(): number;
13
+ get wwwAuthenticate(): string | undefined;
14
+ }
15
+ export interface RevocationTokenResolvers {
16
+ findAccessToken(token: string): Promise<AccessTokenInfo | null>;
17
+ revokeAccessToken(token: string): Promise<void>;
18
+ findRefreshToken?(token: string): Promise<RefreshTokenInfo | null>;
19
+ revokeRefreshToken?(token: string): Promise<void>;
20
+ revokeAccessTokensByGrantId?(grantId: string): Promise<void>;
21
+ }
22
+ export interface RevocationRequestContext {
23
+ params: {
24
+ token?: string;
25
+ token_type_hint?: string;
26
+ };
27
+ authenticatedClientId: string;
28
+ resolvers: RevocationTokenResolvers;
29
+ }
30
+ export type ResolvedRevocationToken = {
31
+ tokenType: 'access_token';
32
+ accessToken: AccessTokenInfo;
33
+ } | {
34
+ tokenType: 'refresh_token';
35
+ refreshToken: RefreshTokenInfo;
36
+ };
37
+ export interface ResolveRevocationTargetOptions {
38
+ token: string;
39
+ tokenTypeHint?: string;
40
+ resolvers: RevocationTokenResolvers;
41
+ }
42
+ export declare function requireRevocationToken(params: {
43
+ token?: string;
44
+ }): string;
45
+ export declare function requireRevocationClient(authenticatedClientId: string): string;
46
+ export declare function resolveRevocationTarget(options: ResolveRevocationTargetOptions): Promise<ResolvedRevocationToken | null>;
47
+ export declare function validateRevocationTokenClient(resolved: ResolvedRevocationToken, authenticatedClientId: string): void;
48
+ export declare function revokeResolvedToken(token: string, resolved: ResolvedRevocationToken, resolvers: RevocationTokenResolvers): Promise<void>;
49
+ export declare function revokeGrantAccessTokens(resolved: ResolvedRevocationToken, resolvers: RevocationTokenResolvers): Promise<void>;
50
+ export declare function handleRevocationRequest(ctx: RevocationRequestContext): Promise<void>;
51
+ //# sourceMappingURL=revocation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revocation.d.ts","sourceRoot":"","sources":["../src/revocation.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D,oBAAY,mBAAmB;IAC7B,cAAc,oBAAoB;IAClC,aAAa,mBAAmB;IAEhC,YAAY,kBAAkB;CAC/B;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACxC,SAAgB,KAAK,EAAE,mBAAmB,CAAC;IAC3C,SAAgB,gBAAgB,EAAE,MAAM,CAAC;gBAE7B,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM;IAShE,IAAI,UAAU,IAAI,MAAM,CAEvB;IAGD,IAAI,eAAe,IAAI,MAAM,GAAG,SAAS,CAKxC;CACF;AAED,MAAM,WAAW,wBAAwB;IACvC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAChE,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,gBAAgB,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACnE,kBAAkB,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAKlD,2BAA2B,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9D;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,qBAAqB,EAAE,MAAM,CAAC;IAC9B,SAAS,EAAE,wBAAwB,CAAC;CACrC;AAMD,MAAM,MAAM,uBAAuB,GAC/B;IAAE,SAAS,EAAE,cAAc,CAAC;IAAC,WAAW,EAAE,eAAe,CAAA;CAAE,GAC3D;IAAE,SAAS,EAAE,eAAe,CAAC;IAAC,YAAY,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAEnE,MAAM,WAAW,8BAA8B;IAC7C,KAAK,EAAE,MAAM,CAAC;IAEd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,wBAAwB,CAAC;CACrC;AAQD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAQzE;AAQD,wBAAgB,uBAAuB,CAAC,qBAAqB,EAAE,MAAM,GAAG,MAAM,CAQ7E;AAcD,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,8BAA8B,GACtC,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAqBzC;AAWD,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,uBAAuB,EACjC,qBAAqB,EAAE,MAAM,GAC5B,IAAI,CAYN;AASD,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,uBAAuB,EACjC,SAAS,EAAE,wBAAwB,GAClC,OAAO,CAAC,IAAI,CAAC,CAMf;AAWD,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,uBAAuB,EACjC,SAAS,EAAE,wBAAwB,GAClC,OAAO,CAAC,IAAI,CAAC,CAGf;AAeD,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,wBAAwB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAcf"}
@@ -0,0 +1,93 @@
1
+ import { sanitizeErrorDescription } from './error-utils.js';
2
+ export var RevocationErrorCode;
3
+ (function (RevocationErrorCode) {
4
+ RevocationErrorCode["InvalidRequest"] = "invalid_request";
5
+ RevocationErrorCode["InvalidClient"] = "invalid_client";
6
+ RevocationErrorCode["InvalidGrant"] = "invalid_grant";
7
+ })(RevocationErrorCode || (RevocationErrorCode = {}));
8
+ export class RevocationError extends Error {
9
+ error;
10
+ errorDescription;
11
+ constructor(error, errorDescription) {
12
+ const sanitized = sanitizeErrorDescription(errorDescription);
13
+ super(sanitized);
14
+ this.name = 'RevocationError';
15
+ this.error = error;
16
+ this.errorDescription = sanitized;
17
+ }
18
+ get statusCode() {
19
+ return this.error === RevocationErrorCode.InvalidClient ? 401 : 400;
20
+ }
21
+ get wwwAuthenticate() {
22
+ if (this.error === RevocationErrorCode.InvalidClient) {
23
+ return 'Basic realm="Client Authentication"';
24
+ }
25
+ return undefined;
26
+ }
27
+ }
28
+ export function requireRevocationToken(params) {
29
+ if (!params.token) {
30
+ throw new RevocationError(RevocationErrorCode.InvalidRequest, 'Missing required parameter: token');
31
+ }
32
+ return params.token;
33
+ }
34
+ export function requireRevocationClient(authenticatedClientId) {
35
+ if (!authenticatedClientId) {
36
+ throw new RevocationError(RevocationErrorCode.InvalidClient, 'Client authentication required');
37
+ }
38
+ return authenticatedClientId;
39
+ }
40
+ export async function resolveRevocationTarget(options) {
41
+ const { token, tokenTypeHint, resolvers } = options;
42
+ const findRefresh = resolvers.findRefreshToken;
43
+ const canRevokeRefresh = findRefresh !== undefined && resolvers.revokeRefreshToken !== undefined;
44
+ const resolveAccess = async () => {
45
+ const info = await resolvers.findAccessToken(token);
46
+ return info ? { tokenType: 'access_token', accessToken: info } : null;
47
+ };
48
+ const resolveRefresh = async () => {
49
+ if (!canRevokeRefresh || !findRefresh)
50
+ return null;
51
+ const info = await findRefresh(token);
52
+ return info ? { tokenType: 'refresh_token', refreshToken: info } : null;
53
+ };
54
+ if (tokenTypeHint === 'refresh_token') {
55
+ return (await resolveRefresh()) ?? (await resolveAccess());
56
+ }
57
+ return (await resolveAccess()) ?? (await resolveRefresh());
58
+ }
59
+ export function validateRevocationTokenClient(resolved, authenticatedClientId) {
60
+ const clientId = resolved.tokenType === 'access_token'
61
+ ? resolved.accessToken.clientId
62
+ : resolved.refreshToken.clientId;
63
+ if (clientId !== authenticatedClientId) {
64
+ throw new RevocationError(RevocationErrorCode.InvalidGrant, 'Token was not issued to the requesting client');
65
+ }
66
+ }
67
+ export async function revokeResolvedToken(token, resolved, resolvers) {
68
+ if (resolved.tokenType === 'access_token') {
69
+ await resolvers.revokeAccessToken(token);
70
+ return;
71
+ }
72
+ await resolvers.revokeRefreshToken?.(token);
73
+ }
74
+ export async function revokeGrantAccessTokens(resolved, resolvers) {
75
+ if (resolved.tokenType !== 'refresh_token')
76
+ return;
77
+ await resolvers.revokeAccessTokensByGrantId?.(resolved.refreshToken.grantId);
78
+ }
79
+ export async function handleRevocationRequest(ctx) {
80
+ const token = requireRevocationToken(ctx.params);
81
+ requireRevocationClient(ctx.authenticatedClientId);
82
+ const resolved = await resolveRevocationTarget({
83
+ token,
84
+ tokenTypeHint: ctx.params.token_type_hint,
85
+ resolvers: ctx.resolvers,
86
+ });
87
+ if (resolved === null)
88
+ return;
89
+ validateRevocationTokenClient(resolved, ctx.authenticatedClientId);
90
+ await revokeResolvedToken(token, resolved, ctx.resolvers);
91
+ await revokeGrantAccessTokens(resolved, ctx.resolvers);
92
+ }
93
+ //# sourceMappingURL=revocation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revocation.js","sourceRoot":"","sources":["../src/revocation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { webcrypto } from 'node:crypto';
2
+ export interface SigningKey {
3
+ privateKey: CryptoKey;
4
+ publicJwk: webcrypto.JsonWebKey;
5
+ keyId: string;
6
+ }
7
+ export interface SigningKeyProvider {
8
+ getSigningKey(): Promise<SigningKey>;
9
+ getSigningKeys?(): Promise<SigningKey[]>;
10
+ }
11
+ export declare function getRegisteredSigningKeys(provider: SigningKeyProvider): Promise<SigningKey[]>;
12
+ export declare function selectSigningKeyByAlg(keys: readonly SigningKey[], requestedAlg: string | undefined): SigningKey;
13
+ export declare function assertHasRs256Key(keys: CryptoKey[]): void;
14
+ export declare function assertKidStrategyConsistent(keys: readonly SigningKey[]): void;
15
+ export interface KeyStrengthPolicy {
16
+ minRsaModulusBits?: number;
17
+ allowedCurves?: readonly string[];
18
+ }
19
+ export declare function assertKeyStrength(keys: readonly SigningKey[], policy?: KeyStrengthPolicy): void;
20
+ export declare function createCachedSigningKeyProvider(base: SigningKeyProvider, ttlMs: number): SigningKeyProvider;
21
+ //# sourceMappingURL=signing-key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signing-key.d.ts","sourceRoot":"","sources":["../src/signing-key.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,SAAS,CAAC;IACtB,SAAS,EAAE,SAAS,CAAC,UAAU,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;CACf;AAeD,MAAM,WAAW,kBAAkB;IACjC,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;IACrC,cAAc,CAAC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;CAC1C;AASD,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAAC,UAAU,EAAE,CAAC,CAKvB;AAcD,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,SAAS,UAAU,EAAE,EAC3B,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,UAAU,CAiBZ;AAWD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI,CAazD;AAcD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,GAAG,IAAI,CAc7E;AASD,MAAM,WAAW,iBAAiB;IAEhC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AA8BD,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,SAAS,UAAU,EAAE,EAC3B,MAAM,CAAC,EAAE,iBAAiB,GACzB,IAAI,CAmCN;AAWD,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,kBAAkB,EACxB,KAAK,EAAE,MAAM,GACZ,kBAAkB,CAsBpB"}
@@ -0,0 +1,99 @@
1
+ import { getJwaAlgorithm, rsaModulusBitLength } from './crypto-utils.js';
2
+ export async function getRegisteredSigningKeys(provider) {
3
+ if (provider.getSigningKeys) {
4
+ return provider.getSigningKeys();
5
+ }
6
+ return [await provider.getSigningKey()];
7
+ }
8
+ export function selectSigningKeyByAlg(keys, requestedAlg) {
9
+ if (keys.length === 0) {
10
+ throw new Error('No signing keys available');
11
+ }
12
+ const alg = requestedAlg ?? 'RS256';
13
+ for (let i = keys.length - 1; i >= 0; i--) {
14
+ const key = keys[i];
15
+ try {
16
+ if (getJwaAlgorithm(key.privateKey) === alg) {
17
+ return key;
18
+ }
19
+ }
20
+ catch {
21
+ }
22
+ }
23
+ throw new Error(`No signing key registered for alg "${alg}"`);
24
+ }
25
+ export function assertHasRs256Key(keys) {
26
+ for (const key of keys) {
27
+ try {
28
+ if (getJwaAlgorithm(key) === 'RS256') {
29
+ return;
30
+ }
31
+ }
32
+ catch {
33
+ }
34
+ }
35
+ throw new Error('OIDC Core 1.0 §15.1 violation: at least one RS256 (RSASSA-PKCS1-v1_5 with SHA-256) key is required');
36
+ }
37
+ export function assertKidStrategyConsistent(keys) {
38
+ if (keys.length <= 1)
39
+ return;
40
+ const seen = new Set();
41
+ for (const key of keys) {
42
+ if (!key.keyId) {
43
+ throw new Error('Multiple signing keys are published but a key has an empty kid (RFC 7517 §4.5)');
44
+ }
45
+ if (seen.has(key.keyId)) {
46
+ throw new Error(`Duplicate kid in signing key set: ${key.keyId} (RFC 7517 §4.5)`);
47
+ }
48
+ seen.add(key.keyId);
49
+ }
50
+ }
51
+ const DEFAULT_MIN_RSA_MODULUS_BITS = 2048;
52
+ const DEFAULT_ALLOWED_CURVES = ['P-256', 'P-384', 'P-521'];
53
+ export function assertKeyStrength(keys, policy) {
54
+ const minRsaModulusBits = policy?.minRsaModulusBits ?? DEFAULT_MIN_RSA_MODULUS_BITS;
55
+ const allowedCurves = policy?.allowedCurves ?? DEFAULT_ALLOWED_CURVES;
56
+ for (const key of keys) {
57
+ const jwk = key.publicJwk;
58
+ if (jwk.kty === 'RSA') {
59
+ if (!jwk.n) {
60
+ throw new Error(`Signing key "${key.keyId}" is an RSA key but its public JWK has no modulus (n)`);
61
+ }
62
+ const bits = rsaModulusBitLength(jwk.n);
63
+ if (bits < minRsaModulusBits) {
64
+ throw new Error(`Signing key "${key.keyId}" has a ${bits}-bit RSA modulus; minimum allowed is ${minRsaModulusBits} bits (NIST SP 800-131A Rev.2)`);
65
+ }
66
+ continue;
67
+ }
68
+ if (jwk.kty === 'EC') {
69
+ if (!jwk.crv || !allowedCurves.includes(jwk.crv)) {
70
+ throw new Error(`Signing key "${key.keyId}" uses unsupported EC curve "${jwk.crv ?? '(missing)'}"; allowed curves: ${allowedCurves.join(', ')}`);
71
+ }
72
+ continue;
73
+ }
74
+ throw new Error(`Signing key "${key.keyId}" uses unsupported key type "${jwk.kty ?? '(missing)'}"`);
75
+ }
76
+ }
77
+ export function createCachedSigningKeyProvider(base, ttlMs) {
78
+ let singleCache = null;
79
+ let multiCache = null;
80
+ return {
81
+ async getSigningKey() {
82
+ if (!singleCache || Date.now() > singleCache.expiresAt) {
83
+ const key = await base.getSigningKey();
84
+ singleCache = { key, expiresAt: Date.now() + ttlMs };
85
+ }
86
+ return singleCache.key;
87
+ },
88
+ async getSigningKeys() {
89
+ if (!multiCache || Date.now() > multiCache.expiresAt) {
90
+ const keys = base.getSigningKeys
91
+ ? await base.getSigningKeys()
92
+ : [await base.getSigningKey()];
93
+ multiCache = { keys, expiresAt: Date.now() + ttlMs };
94
+ }
95
+ return multiCache.keys;
96
+ },
97
+ };
98
+ }
99
+ //# sourceMappingURL=signing-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signing-key.js","sourceRoot":"","sources":["../src/signing-key.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export declare enum TokenErrorCode {
2
+ InvalidRequest = "invalid_request",
3
+ InvalidClient = "invalid_client",
4
+ InvalidGrant = "invalid_grant",
5
+ UnauthorizedClient = "unauthorized_client",
6
+ UnsupportedGrantType = "unsupported_grant_type",
7
+ InvalidScope = "invalid_scope"
8
+ }
9
+ export declare class TokenError extends Error {
10
+ readonly error: TokenErrorCode;
11
+ readonly errorDescription: string;
12
+ constructor(error: TokenErrorCode, errorDescription: string);
13
+ get statusCode(): number;
14
+ get wwwAuthenticate(): string | undefined;
15
+ }
16
+ //# sourceMappingURL=token-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-error.d.ts","sourceRoot":"","sources":["../src/token-error.ts"],"names":[],"mappings":"AAMA,oBAAY,cAAc;IACxB,cAAc,oBAAoB;IAClC,aAAa,mBAAmB;IAChC,YAAY,kBAAkB;IAC9B,kBAAkB,wBAAwB;IAC1C,oBAAoB,2BAA2B;IAC/C,YAAY,kBAAkB;CAC/B;AAKD,qBAAa,UAAW,SAAQ,KAAK;IACnC,SAAgB,KAAK,EAAE,cAAc,CAAC;IACtC,SAAgB,gBAAgB,EAAE,MAAM,CAAC;gBAE7B,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM;IAc3D,IAAI,UAAU,IAAI,MAAM,CAEvB;IAOD,IAAI,eAAe,IAAI,MAAM,GAAG,SAAS,CAKxC;CACF"}
@@ -0,0 +1,31 @@
1
+ import { sanitizeErrorDescription } from './error-utils.js';
2
+ export var TokenErrorCode;
3
+ (function (TokenErrorCode) {
4
+ TokenErrorCode["InvalidRequest"] = "invalid_request";
5
+ TokenErrorCode["InvalidClient"] = "invalid_client";
6
+ TokenErrorCode["InvalidGrant"] = "invalid_grant";
7
+ TokenErrorCode["UnauthorizedClient"] = "unauthorized_client";
8
+ TokenErrorCode["UnsupportedGrantType"] = "unsupported_grant_type";
9
+ TokenErrorCode["InvalidScope"] = "invalid_scope";
10
+ })(TokenErrorCode || (TokenErrorCode = {}));
11
+ export class TokenError extends Error {
12
+ error;
13
+ errorDescription;
14
+ constructor(error, errorDescription) {
15
+ const sanitized = sanitizeErrorDescription(errorDescription);
16
+ super(sanitized);
17
+ this.name = 'TokenError';
18
+ this.error = error;
19
+ this.errorDescription = sanitized;
20
+ }
21
+ get statusCode() {
22
+ return this.error === TokenErrorCode.InvalidClient ? 401 : 400;
23
+ }
24
+ get wwwAuthenticate() {
25
+ if (this.error === TokenErrorCode.InvalidClient) {
26
+ return 'Basic realm="Client Authentication"';
27
+ }
28
+ return undefined;
29
+ }
30
+ }
31
+ //# sourceMappingURL=token-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-error.js","sourceRoot":"","sources":["../src/token-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAM5D,MAAM,CAAN,IAAY,cAOX;AAPD,WAAY,cAAc;IACxB,oDAAkC,CAAA;IAClC,kDAAgC,CAAA;IAChC,gDAA8B,CAAA;IAC9B,4DAA0C,CAAA;IAC1C,iEAA+C,CAAA;IAC/C,gDAA8B,CAAA;AAChC,CAAC,EAPW,cAAc,KAAd,cAAc,QAOzB;AAKD,MAAM,OAAO,UAAW,SAAQ,KAAK;IACnB,KAAK,CAAiB;IACtB,gBAAgB,CAAS;IAEzC,YAAY,KAAqB,EAAE,gBAAwB;QAGzD,MAAM,SAAS,GAAG,wBAAwB,CAAC,gBAAgB,CAAC,CAAC;QAC7D,KAAK,CAAC,SAAS,CAAC,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;IACpC,CAAC;IAMD,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,KAAK,KAAK,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IACjE,CAAC;IAOD,IAAI,eAAe;QACjB,IAAI,IAAI,CAAC,KAAK,KAAK,cAAc,CAAC,aAAa,EAAE,CAAC;YAChD,OAAO,qCAAqC,CAAC;QAC/C,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;CACF"}