@maronn-openid-connect/experimental 0.0.3 → 0.0.5
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/README.md +7 -0
- package/dist/device-authorization-grant/device-authorization-request.d.ts +41 -0
- package/dist/device-authorization-grant/device-authorization-request.d.ts.map +1 -0
- package/dist/device-authorization-grant/device-authorization-request.js +80 -0
- package/dist/device-authorization-grant/device-authorization-request.js.map +1 -0
- package/dist/device-authorization-grant/device-code-grant.d.ts +23 -0
- package/dist/device-authorization-grant/device-code-grant.d.ts.map +1 -0
- package/dist/device-authorization-grant/device-code-grant.js +63 -0
- package/dist/device-authorization-grant/device-code-grant.js.map +1 -0
- package/dist/device-authorization-grant/errors.d.ts +12 -0
- package/dist/device-authorization-grant/errors.d.ts.map +1 -0
- package/dist/device-authorization-grant/errors.js +24 -0
- package/dist/device-authorization-grant/errors.js.map +1 -0
- package/dist/device-authorization-grant/index.d.ts +11 -0
- package/dist/device-authorization-grant/index.d.ts.map +1 -0
- package/dist/device-authorization-grant/index.js +7 -0
- package/dist/device-authorization-grant/index.js.map +1 -0
- package/dist/device-authorization-grant/store.d.ts +33 -0
- package/dist/device-authorization-grant/store.d.ts.map +1 -0
- package/dist/device-authorization-grant/store.js +5 -0
- package/dist/device-authorization-grant/store.js.map +1 -0
- package/dist/device-authorization-grant/user-code.d.ts +9 -0
- package/dist/device-authorization-grant/user-code.d.ts.map +1 -0
- package/dist/device-authorization-grant/user-code.js +39 -0
- package/dist/device-authorization-grant/user-code.js.map +1 -0
- package/dist/device-authorization-grant/verification.d.ts +26 -0
- package/dist/device-authorization-grant/verification.d.ts.map +1 -0
- package/dist/device-authorization-grant/verification.js +88 -0
- package/dist/device-authorization-grant/verification.js.map +1 -0
- package/dist/jarm/index.d.ts +6 -0
- package/dist/jarm/index.d.ts.map +1 -0
- package/dist/jarm/index.js +3 -0
- package/dist/jarm/index.js.map +1 -0
- package/dist/jarm/response-jwt.d.ts +12 -0
- package/dist/jarm/response-jwt.d.ts.map +1 -0
- package/dist/jarm/response-jwt.js +49 -0
- package/dist/jarm/response-jwt.js.map +1 -0
- package/dist/jarm/response-mode.d.ts +13 -0
- package/dist/jarm/response-mode.d.ts.map +1 -0
- package/dist/jarm/response-mode.js +16 -0
- package/dist/jarm/response-mode.js.map +1 -0
- package/dist/token-exchange/index.d.ts +1 -1
- package/dist/token-exchange/index.d.ts.map +1 -1
- package/dist/token-exchange/index.js +1 -1
- package/dist/token-exchange/index.js.map +1 -1
- package/dist/token-exchange/token-exchange-request.d.ts +19 -0
- package/dist/token-exchange/token-exchange-request.d.ts.map +1 -1
- package/dist/token-exchange/token-exchange-request.js +52 -14
- package/dist/token-exchange/token-exchange-request.js.map +1 -1
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|---|---|---|---|
|
|
15
15
|
| `par` | Pushed Authorization Requests | RFC 9126 | `@maronn-openid-connect/experimental/par` |
|
|
16
16
|
| `token-exchange` | OAuth 2.0 Token Exchange (impersonation) | RFC 8693 | `@maronn-openid-connect/experimental/token-exchange` |
|
|
17
|
+
| `jarm` | JWT Secured Authorization Response Mode (signed `query.jwt` only) | JARM (OpenID Foundation Final, 2022-11-09) | `@maronn-openid-connect/experimental/jarm` |
|
|
18
|
+
| `device-authorization-grant` | OAuth 2.0 Device Authorization Grant | RFC 8628 | `@maronn-openid-connect/experimental/device-authorization-grant` |
|
|
17
19
|
|
|
18
20
|
機能ごとに subpath export で提供します。ルート (`.`) からの再エクスポートは提供しません。機能間でコードを共有しないことで、昇格・削除時に他機能へ影響しない構造を保っています。
|
|
19
21
|
|
|
@@ -63,3 +65,8 @@ Experimental 機能が core へ昇格する目安は次のとおりです。
|
|
|
63
65
|
## 利用者ドキュメント
|
|
64
66
|
|
|
65
67
|
`docs/library-document` の Experimental セクションを参照してください。
|
|
68
|
+
|
|
69
|
+
## 実装解説
|
|
70
|
+
|
|
71
|
+
各機能を「何を・どう実装したか」をコード全文つきで説明する解説(日本語・英語)を
|
|
72
|
+
`docs/implementation-guides/experimental/` に置いています。実装の内側を読むときはこちらを参照してください。
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type DeviceAuthorizationRecord, type DeviceAuthorizationStore } from './store.js';
|
|
2
|
+
export declare const DEFAULT_DEVICE_CODE_EXPIRES_IN = 600;
|
|
3
|
+
export declare const DEFAULT_POLL_INTERVAL = 5;
|
|
4
|
+
export interface DeviceAuthorizationClient {
|
|
5
|
+
clientId: string;
|
|
6
|
+
grantTypes?: string[];
|
|
7
|
+
}
|
|
8
|
+
export interface DeviceAuthorizationResponse {
|
|
9
|
+
device_code: string;
|
|
10
|
+
user_code: string;
|
|
11
|
+
verification_uri: string;
|
|
12
|
+
verification_uri_complete: string;
|
|
13
|
+
expires_in: number;
|
|
14
|
+
interval: number;
|
|
15
|
+
}
|
|
16
|
+
export declare function validateDeviceGrantAllowed(client: DeviceAuthorizationClient): void;
|
|
17
|
+
export declare function validateDeviceAuthorizationScope(scope: string | undefined): string[];
|
|
18
|
+
export declare function applyOfflineAccessPolicy(scope: string[], options: {
|
|
19
|
+
client: DeviceAuthorizationClient;
|
|
20
|
+
refreshTokenFeatureEnabled: boolean;
|
|
21
|
+
}): string[];
|
|
22
|
+
export declare function createDeviceAuthorizationRecord(options: {
|
|
23
|
+
clientId: string;
|
|
24
|
+
scope: string[];
|
|
25
|
+
store: DeviceAuthorizationStore;
|
|
26
|
+
expiresIn: number;
|
|
27
|
+
interval: number;
|
|
28
|
+
now?: Date;
|
|
29
|
+
}): Promise<DeviceAuthorizationRecord>;
|
|
30
|
+
export declare function buildDeviceAuthorizationResponse(record: DeviceAuthorizationRecord, issuer: string): DeviceAuthorizationResponse;
|
|
31
|
+
export declare function processDeviceAuthorizationRequest(input: {
|
|
32
|
+
params: Record<string, string>;
|
|
33
|
+
client: DeviceAuthorizationClient;
|
|
34
|
+
issuer: string;
|
|
35
|
+
expiresIn?: number;
|
|
36
|
+
interval?: number;
|
|
37
|
+
refreshTokenFeatureEnabled: boolean;
|
|
38
|
+
store: DeviceAuthorizationStore;
|
|
39
|
+
now?: Date;
|
|
40
|
+
}): Promise<DeviceAuthorizationResponse>;
|
|
41
|
+
//# sourceMappingURL=device-authorization-request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-authorization-request.d.ts","sourceRoot":"","sources":["../../src/device-authorization-grant/device-authorization-request.ts"],"names":[],"mappings":"AAgBA,OAAO,EAEL,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC9B,MAAM,YAAY,CAAC;AAMpB,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAElD,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAGvC,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IAEjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAGD,MAAM,WAAW,2BAA2B;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,yBAAyB,EAAE,MAAM,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AASD,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,yBAAyB,GAAG,IAAI,CAQlF;AAaD,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAepF;AAUD,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,EAAE;IAAE,MAAM,EAAE,yBAAyB,CAAC;IAAC,0BAA0B,EAAE,OAAO,CAAA;CAAE,GAClF,MAAM,EAAE,CAMV;AAOD,wBAAsB,+BAA+B,CAAC,OAAO,EAAE;IAC7D,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,wBAAwB,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAoBrC;AASD,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,yBAAyB,EACjC,MAAM,EAAE,MAAM,GACb,2BAA2B,CAU7B;AAUD,wBAAsB,iCAAiC,CAAC,KAAK,EAAE;IAC7D,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,MAAM,EAAE,yBAAyB,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0BAA0B,EAAE,OAAO,CAAC;IACpC,KAAK,EAAE,wBAAwB,CAAC;IAChC,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAmBvC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { generateRandomString } from '@maronn-openid-connect/core';
|
|
2
|
+
import { DeviceAuthorizationError } from './errors.js';
|
|
3
|
+
import { generateUniqueUserCode } from './user-code.js';
|
|
4
|
+
import { DEVICE_CODE_GRANT_TYPE, } from './store.js';
|
|
5
|
+
const DEVICE_CODE_BYTE_LENGTH = 32;
|
|
6
|
+
export const DEFAULT_DEVICE_CODE_EXPIRES_IN = 600;
|
|
7
|
+
export const DEFAULT_POLL_INTERVAL = 5;
|
|
8
|
+
export function validateDeviceGrantAllowed(client) {
|
|
9
|
+
const grantTypes = client.grantTypes ?? [];
|
|
10
|
+
if (!grantTypes.includes(DEVICE_CODE_GRANT_TYPE)) {
|
|
11
|
+
throw new DeviceAuthorizationError('unauthorized_client', 'The client is not authorized to use the device_code grant');
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function validateDeviceAuthorizationScope(scope) {
|
|
15
|
+
if (scope === undefined || scope.trim() === '') {
|
|
16
|
+
throw new DeviceAuthorizationError('invalid_request', 'Missing required parameter: scope');
|
|
17
|
+
}
|
|
18
|
+
const values = [...new Set(scope.trim().split(/\s+/).filter((value) => value.length > 0))];
|
|
19
|
+
if (!values.includes('openid')) {
|
|
20
|
+
throw new DeviceAuthorizationError('invalid_scope', 'The openid scope is required');
|
|
21
|
+
}
|
|
22
|
+
return values;
|
|
23
|
+
}
|
|
24
|
+
export function applyOfflineAccessPolicy(scope, options) {
|
|
25
|
+
const clientAllowsRefresh = (options.client.grantTypes ?? []).includes('refresh_token');
|
|
26
|
+
if (options.refreshTokenFeatureEnabled && clientAllowsRefresh) {
|
|
27
|
+
return scope;
|
|
28
|
+
}
|
|
29
|
+
return scope.filter((value) => value !== 'offline_access');
|
|
30
|
+
}
|
|
31
|
+
export async function createDeviceAuthorizationRecord(options) {
|
|
32
|
+
const { userCode, userCodeDisplay } = await generateUniqueUserCode(options.store);
|
|
33
|
+
const createdAt = options.now ?? new Date();
|
|
34
|
+
const record = {
|
|
35
|
+
deviceCode: generateRandomString(DEVICE_CODE_BYTE_LENGTH),
|
|
36
|
+
userCode,
|
|
37
|
+
userCodeDisplay,
|
|
38
|
+
clientId: options.clientId,
|
|
39
|
+
scope: options.scope,
|
|
40
|
+
status: 'pending',
|
|
41
|
+
createdAt,
|
|
42
|
+
expiresAt: new Date(createdAt.getTime() + options.expiresIn * 1000),
|
|
43
|
+
interval: options.interval,
|
|
44
|
+
lastPolledAt: null,
|
|
45
|
+
csrfToken: null,
|
|
46
|
+
bindingHash: null,
|
|
47
|
+
loginAttempts: 0,
|
|
48
|
+
};
|
|
49
|
+
await options.store.save(record);
|
|
50
|
+
return record;
|
|
51
|
+
}
|
|
52
|
+
export function buildDeviceAuthorizationResponse(record, issuer) {
|
|
53
|
+
const verificationUri = `${issuer}/device`;
|
|
54
|
+
return {
|
|
55
|
+
device_code: record.deviceCode,
|
|
56
|
+
user_code: record.userCodeDisplay,
|
|
57
|
+
verification_uri: verificationUri,
|
|
58
|
+
verification_uri_complete: `${verificationUri}?user_code=${encodeURIComponent(record.userCodeDisplay)}`,
|
|
59
|
+
expires_in: Math.round((record.expiresAt.getTime() - record.createdAt.getTime()) / 1000),
|
|
60
|
+
interval: record.interval,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export async function processDeviceAuthorizationRequest(input) {
|
|
64
|
+
validateDeviceGrantAllowed(input.client);
|
|
65
|
+
const requestedScope = validateDeviceAuthorizationScope(input.params['scope']);
|
|
66
|
+
const scope = applyOfflineAccessPolicy(requestedScope, {
|
|
67
|
+
client: input.client,
|
|
68
|
+
refreshTokenFeatureEnabled: input.refreshTokenFeatureEnabled,
|
|
69
|
+
});
|
|
70
|
+
const record = await createDeviceAuthorizationRecord({
|
|
71
|
+
clientId: input.client.clientId,
|
|
72
|
+
scope,
|
|
73
|
+
store: input.store,
|
|
74
|
+
expiresIn: input.expiresIn ?? DEFAULT_DEVICE_CODE_EXPIRES_IN,
|
|
75
|
+
interval: input.interval ?? DEFAULT_POLL_INTERVAL,
|
|
76
|
+
now: input.now,
|
|
77
|
+
});
|
|
78
|
+
return buildDeviceAuthorizationResponse(record, input.issuer);
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=device-authorization-request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-authorization-request.js","sourceRoot":"","sources":["../../src/device-authorization-grant/device-authorization-request.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type DeviceAuthorizationRecord, type DeviceAuthorizationStore } from './store.js';
|
|
2
|
+
export declare const SLOW_DOWN_INTERVAL_INCREMENT = 5;
|
|
3
|
+
export interface DeviceCodeGrantClient {
|
|
4
|
+
clientId: string;
|
|
5
|
+
grantTypes?: string[];
|
|
6
|
+
}
|
|
7
|
+
export interface DeviceCodeGrantResult {
|
|
8
|
+
subject: string;
|
|
9
|
+
clientId: string;
|
|
10
|
+
scope: string[];
|
|
11
|
+
authTime: number;
|
|
12
|
+
grantId: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function validateDeviceCodeGrantAllowed(client: DeviceCodeGrantClient): void;
|
|
15
|
+
export declare function resolveDeviceCodeRecord(params: Record<string, string>, client: DeviceCodeGrantClient, store: DeviceAuthorizationStore): Promise<DeviceAuthorizationRecord>;
|
|
16
|
+
export declare function evaluateDeviceCodeState(record: DeviceAuthorizationRecord, store: DeviceAuthorizationStore, now?: Date): Promise<DeviceCodeGrantResult>;
|
|
17
|
+
export declare function processDeviceCodeGrant(input: {
|
|
18
|
+
params: Record<string, string>;
|
|
19
|
+
client: DeviceCodeGrantClient;
|
|
20
|
+
store: DeviceAuthorizationStore;
|
|
21
|
+
now?: Date;
|
|
22
|
+
}): Promise<DeviceCodeGrantResult>;
|
|
23
|
+
//# sourceMappingURL=device-code-grant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-code-grant.d.ts","sourceRoot":"","sources":["../../src/device-authorization-grant/device-code-grant.ts"],"names":[],"mappings":"AASA,OAAO,EAEL,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC9B,MAAM,YAAY,CAAC;AAGpB,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAY9C,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAGD,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAOD,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,qBAAqB,GAAG,IAAI,CAOlF;AAUD,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,MAAM,EAAE,qBAAqB,EAC7B,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,yBAAyB,CAAC,CAapC;AAkBD,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,yBAAyB,EACjC,KAAK,EAAE,wBAAwB,EAC/B,GAAG,GAAE,IAAiB,GACrB,OAAO,CAAC,qBAAqB,CAAC,CA6DhC;AAUD,wBAAsB,sBAAsB,CAAC,KAAK,EAAE;IAClD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,MAAM,EAAE,qBAAqB,CAAC;IAC9B,KAAK,EAAE,wBAAwB,CAAC;IAChC,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAIjC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { DeviceAuthorizationError } from './errors.js';
|
|
2
|
+
import { DEVICE_CODE_GRANT_TYPE, } from './store.js';
|
|
3
|
+
export const SLOW_DOWN_INTERVAL_INCREMENT = 5;
|
|
4
|
+
const INVALID_DEVICE_CODE_MESSAGE = 'The device_code is invalid, expired, or was issued to another client';
|
|
5
|
+
export function validateDeviceCodeGrantAllowed(client) {
|
|
6
|
+
if (!(client.grantTypes ?? []).includes(DEVICE_CODE_GRANT_TYPE)) {
|
|
7
|
+
throw new DeviceAuthorizationError('unauthorized_client', 'The client is not authorized to use the device_code grant');
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export async function resolveDeviceCodeRecord(params, client, store) {
|
|
11
|
+
const deviceCode = params['device_code'];
|
|
12
|
+
if (deviceCode === undefined || deviceCode === '') {
|
|
13
|
+
throw new DeviceAuthorizationError('invalid_request', 'Missing required parameter: device_code');
|
|
14
|
+
}
|
|
15
|
+
const record = await store.findByDeviceCode(deviceCode);
|
|
16
|
+
if (record === null || record.clientId !== client.clientId) {
|
|
17
|
+
throw new DeviceAuthorizationError('invalid_grant', INVALID_DEVICE_CODE_MESSAGE);
|
|
18
|
+
}
|
|
19
|
+
return record;
|
|
20
|
+
}
|
|
21
|
+
export async function evaluateDeviceCodeState(record, store, now = new Date()) {
|
|
22
|
+
if (now.getTime() >= record.expiresAt.getTime()) {
|
|
23
|
+
await store.delete(record.deviceCode);
|
|
24
|
+
throw new DeviceAuthorizationError('expired_token', 'The device_code has expired. Start a new device authorization request.');
|
|
25
|
+
}
|
|
26
|
+
if (record.lastPolledAt !== null &&
|
|
27
|
+
now.getTime() - record.lastPolledAt.getTime() < record.interval * 1000) {
|
|
28
|
+
record.interval += SLOW_DOWN_INTERVAL_INCREMENT;
|
|
29
|
+
record.lastPolledAt = now;
|
|
30
|
+
await store.update(record);
|
|
31
|
+
throw new DeviceAuthorizationError('slow_down', 'Polling too frequently. Increase the interval by 5 seconds.');
|
|
32
|
+
}
|
|
33
|
+
if (record.status === 'pending') {
|
|
34
|
+
record.lastPolledAt = now;
|
|
35
|
+
await store.update(record);
|
|
36
|
+
throw new DeviceAuthorizationError('authorization_pending', 'The authorization request is still pending');
|
|
37
|
+
}
|
|
38
|
+
if (record.status === 'denied') {
|
|
39
|
+
await store.delete(record.deviceCode);
|
|
40
|
+
throw new DeviceAuthorizationError('access_denied', 'The end-user denied the authorization request');
|
|
41
|
+
}
|
|
42
|
+
const consumed = await store.consume(record.deviceCode);
|
|
43
|
+
if (consumed === null ||
|
|
44
|
+
consumed.status !== 'approved' ||
|
|
45
|
+
consumed.subject === undefined ||
|
|
46
|
+
consumed.authTime === undefined ||
|
|
47
|
+
consumed.grantId === undefined) {
|
|
48
|
+
throw new DeviceAuthorizationError('invalid_grant', INVALID_DEVICE_CODE_MESSAGE);
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
subject: consumed.subject,
|
|
52
|
+
clientId: consumed.clientId,
|
|
53
|
+
scope: consumed.approvedScope ?? consumed.scope,
|
|
54
|
+
authTime: consumed.authTime,
|
|
55
|
+
grantId: consumed.grantId,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export async function processDeviceCodeGrant(input) {
|
|
59
|
+
validateDeviceCodeGrantAllowed(input.client);
|
|
60
|
+
const record = await resolveDeviceCodeRecord(input.params, input.client, input.store);
|
|
61
|
+
return evaluateDeviceCodeState(record, input.store, input.now);
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=device-code-grant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-code-grant.js","sourceRoot":"","sources":["../../src/device-authorization-grant/device-code-grant.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type DeviceAuthorizationErrorCode = 'authorization_pending' | 'slow_down' | 'access_denied' | 'expired_token' | 'invalid_request' | 'invalid_grant' | 'invalid_scope' | 'unauthorized_client';
|
|
2
|
+
export declare class DeviceAuthorizationError extends Error {
|
|
3
|
+
readonly code: DeviceAuthorizationErrorCode;
|
|
4
|
+
readonly errorDescription: string;
|
|
5
|
+
constructor(code: DeviceAuthorizationErrorCode, errorDescription: string);
|
|
6
|
+
get statusCode(): 400;
|
|
7
|
+
}
|
|
8
|
+
export declare class DeviceVerificationError extends Error {
|
|
9
|
+
readonly statusCode: 401 | 403;
|
|
10
|
+
constructor(message: string, statusCode: 401 | 403);
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/device-authorization-grant/errors.ts"],"names":[],"mappings":"AAkBA,MAAM,MAAM,4BAA4B,GACpC,uBAAuB,GACvB,WAAW,GACX,eAAe,GACf,eAAe,GACf,iBAAiB,GACjB,eAAe,GACf,eAAe,GACf,qBAAqB,CAAC;AAY1B,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,IAAI,EAAE,4BAA4B,CAAC;IAC5C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;gBAEtB,IAAI,EAAE,4BAA4B,EAAE,gBAAgB,EAAE,MAAM;IAUxE,IAAI,UAAU,IAAI,GAAG,CAEpB;CACF;AAQD,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,UAAU,EAAE,GAAG,GAAG,GAAG,CAAC;gBAEnB,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,GAAG,GAAG;CAKnD"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { sanitizeErrorDescription } from '@maronn-openid-connect/core';
|
|
2
|
+
export class DeviceAuthorizationError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
errorDescription;
|
|
5
|
+
constructor(code, errorDescription) {
|
|
6
|
+
const sanitized = sanitizeErrorDescription(errorDescription);
|
|
7
|
+
super(sanitized);
|
|
8
|
+
this.name = 'DeviceAuthorizationError';
|
|
9
|
+
this.code = code;
|
|
10
|
+
this.errorDescription = sanitized;
|
|
11
|
+
}
|
|
12
|
+
get statusCode() {
|
|
13
|
+
return 400;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export class DeviceVerificationError extends Error {
|
|
17
|
+
statusCode;
|
|
18
|
+
constructor(message, statusCode) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.name = 'DeviceVerificationError';
|
|
21
|
+
this.statusCode = statusCode;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/device-authorization-grant/errors.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AA8BvE,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACxC,IAAI,CAA+B;IACnC,gBAAgB,CAAS;IAElC,YAAY,IAAkC,EAAE,gBAAwB;QAEtE,MAAM,SAAS,GAAG,wBAAwB,CAAC,gBAAgB,CAAC,CAAC;QAC7D,KAAK,CAAC,SAAS,CAAC,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;QACvC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;IACpC,CAAC;IAGD,IAAI,UAAU;QACZ,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AAQD,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IACvC,UAAU,CAAY;IAE/B,YAAY,OAAe,EAAE,UAAqB;QAChD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;QACtC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { DEVICE_CODE_GRANT_TYPE, USER_CODE_CHARSET, USER_CODE_GROUP_SIZE, USER_CODE_LENGTH, } from './store.js';
|
|
2
|
+
export type { DeviceAuthorizationRecord, DeviceAuthorizationStatus, DeviceAuthorizationStore, } from './store.js';
|
|
3
|
+
export { DeviceAuthorizationError, DeviceVerificationError } from './errors.js';
|
|
4
|
+
export type { DeviceAuthorizationErrorCode } from './errors.js';
|
|
5
|
+
export { formatUserCode, generateUniqueUserCode, generateUserCode, normalizeUserCode, } from './user-code.js';
|
|
6
|
+
export { DEFAULT_DEVICE_CODE_EXPIRES_IN, DEFAULT_POLL_INTERVAL, applyOfflineAccessPolicy, buildDeviceAuthorizationResponse, createDeviceAuthorizationRecord, processDeviceAuthorizationRequest, validateDeviceAuthorizationScope, validateDeviceGrantAllowed, } from './device-authorization-request.js';
|
|
7
|
+
export type { DeviceAuthorizationClient, DeviceAuthorizationResponse, } from './device-authorization-request.js';
|
|
8
|
+
export { INVALID_USER_CODE_MESSAGE, approveDeviceAuthorization, denyDeviceAuthorization, findPendingRecordByUserCode, issueVerificationBinding, recordDeviceLoginFailure, validateVerificationBinding, validateVerificationCsrfToken, } from './verification.js';
|
|
9
|
+
export { SLOW_DOWN_INTERVAL_INCREMENT, evaluateDeviceCodeState, processDeviceCodeGrant, resolveDeviceCodeRecord, validateDeviceCodeGrantAllowed, } from './device-code-grant.js';
|
|
10
|
+
export type { DeviceCodeGrantClient, DeviceCodeGrantResult, } from './device-code-grant.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/device-authorization-grant/index.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,yBAAyB,EACzB,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAChF,YAAY,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,8BAA8B,EAC9B,qBAAqB,EACrB,wBAAwB,EACxB,gCAAgC,EAChC,+BAA+B,EAC/B,iCAAiC,EACjC,gCAAgC,EAChC,0BAA0B,GAC3B,MAAM,mCAAmC,CAAC;AAC3C,YAAY,EACV,yBAAyB,EACzB,2BAA2B,GAC5B,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EACL,yBAAyB,EACzB,0BAA0B,EAC1B,uBAAuB,EACvB,2BAA2B,EAC3B,wBAAwB,EACxB,wBAAwB,EACxB,2BAA2B,EAC3B,6BAA6B,GAC9B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,8BAA8B,GAC/B,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { DEVICE_CODE_GRANT_TYPE, USER_CODE_CHARSET, USER_CODE_GROUP_SIZE, USER_CODE_LENGTH, } from './store.js';
|
|
2
|
+
export { DeviceAuthorizationError, DeviceVerificationError } from './errors.js';
|
|
3
|
+
export { formatUserCode, generateUniqueUserCode, generateUserCode, normalizeUserCode, } from './user-code.js';
|
|
4
|
+
export { DEFAULT_DEVICE_CODE_EXPIRES_IN, DEFAULT_POLL_INTERVAL, applyOfflineAccessPolicy, buildDeviceAuthorizationResponse, createDeviceAuthorizationRecord, processDeviceAuthorizationRequest, validateDeviceAuthorizationScope, validateDeviceGrantAllowed, } from './device-authorization-request.js';
|
|
5
|
+
export { INVALID_USER_CODE_MESSAGE, approveDeviceAuthorization, denyDeviceAuthorization, findPendingRecordByUserCode, issueVerificationBinding, recordDeviceLoginFailure, validateVerificationBinding, validateVerificationCsrfToken, } from './verification.js';
|
|
6
|
+
export { SLOW_DOWN_INTERVAL_INCREMENT, evaluateDeviceCodeState, processDeviceCodeGrant, resolveDeviceCodeRecord, validateDeviceCodeGrantAllowed, } from './device-code-grant.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/device-authorization-grant/index.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AAOpB,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAGhF,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,8BAA8B,EAC9B,qBAAqB,EACrB,wBAAwB,EACxB,gCAAgC,EAChC,+BAA+B,EAC/B,iCAAiC,EACjC,gCAAgC,EAChC,0BAA0B,GAC3B,MAAM,mCAAmC,CAAC;AAM3C,OAAO,EACL,yBAAyB,EACzB,0BAA0B,EAC1B,uBAAuB,EACvB,2BAA2B,EAC3B,wBAAwB,EACxB,wBAAwB,EACxB,2BAA2B,EAC3B,6BAA6B,GAC9B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,8BAA8B,GAC/B,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export declare const DEVICE_CODE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
2
|
+
export declare const USER_CODE_CHARSET = "BCDFGHJKLMNPQRSTVWXZ";
|
|
3
|
+
export declare const USER_CODE_LENGTH = 8;
|
|
4
|
+
export declare const USER_CODE_GROUP_SIZE = 4;
|
|
5
|
+
export type DeviceAuthorizationStatus = 'pending' | 'approved' | 'denied';
|
|
6
|
+
export interface DeviceAuthorizationRecord {
|
|
7
|
+
deviceCode: string;
|
|
8
|
+
userCode: string;
|
|
9
|
+
userCodeDisplay: string;
|
|
10
|
+
clientId: string;
|
|
11
|
+
scope: string[];
|
|
12
|
+
status: DeviceAuthorizationStatus;
|
|
13
|
+
createdAt: Date;
|
|
14
|
+
expiresAt: Date;
|
|
15
|
+
interval: number;
|
|
16
|
+
lastPolledAt: Date | null;
|
|
17
|
+
csrfToken: string | null;
|
|
18
|
+
bindingHash: string | null;
|
|
19
|
+
loginAttempts: number;
|
|
20
|
+
subject?: string;
|
|
21
|
+
authTime?: number;
|
|
22
|
+
approvedScope?: string[];
|
|
23
|
+
grantId?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface DeviceAuthorizationStore {
|
|
26
|
+
save(record: DeviceAuthorizationRecord): Promise<void>;
|
|
27
|
+
findByDeviceCode(deviceCode: string): Promise<DeviceAuthorizationRecord | null>;
|
|
28
|
+
findByUserCode(userCode: string): Promise<DeviceAuthorizationRecord | null>;
|
|
29
|
+
update(record: DeviceAuthorizationRecord): Promise<void>;
|
|
30
|
+
delete(deviceCode: string): Promise<void>;
|
|
31
|
+
consume(deviceCode: string): Promise<DeviceAuthorizationRecord | null>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/device-authorization-grant/store.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,sBAAsB,iDAAiD,CAAC;AASrF,eAAO,MAAM,iBAAiB,yBAAyB,CAAC;AAGxD,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAGlC,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAGtC,MAAM,MAAM,yBAAyB,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;AAQ1E,MAAM,WAAW,yBAAyB;IAExC,UAAU,EAAE,MAAM,CAAC;IAEnB,QAAQ,EAAE,MAAM,CAAC;IAEjB,eAAe,EAAE,MAAM,CAAC;IAExB,QAAQ,EAAE,MAAM,CAAC;IAEjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,yBAAyB,CAAC;IAClC,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAEhB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,IAAI,GAAG,IAAI,CAAC;IAE1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAKzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3B,aAAa,EAAE,MAAM,CAAC;IAEtB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AASD,MAAM,WAAW,wBAAwB;IACvC,IAAI,CAAC,MAAM,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAAC;IAEhF,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAAC;IAS5E,MAAM,CAAC,MAAM,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAc1C,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAAC;CACxE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/device-authorization-grant/store.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,sBAAsB,GAAG,8CAA8C,CAAC;AASrF,MAAM,CAAC,MAAM,iBAAiB,GAAG,sBAAsB,CAAC;AAGxD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAGlC,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type DeviceAuthorizationStore } from './store.js';
|
|
2
|
+
export declare function generateUserCode(): string;
|
|
3
|
+
export declare function formatUserCode(normalized: string): string;
|
|
4
|
+
export declare function normalizeUserCode(input: string): string;
|
|
5
|
+
export declare function generateUniqueUserCode(store: DeviceAuthorizationStore, maxAttempts?: number): Promise<{
|
|
6
|
+
userCode: string;
|
|
7
|
+
userCodeDisplay: string;
|
|
8
|
+
}>;
|
|
9
|
+
//# sourceMappingURL=user-code.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-code.d.ts","sourceRoot":"","sources":["../../src/device-authorization-grant/user-code.ts"],"names":[],"mappings":"AAOA,OAAO,EAIL,KAAK,wBAAwB,EAC9B,MAAM,YAAY,CAAC;AAapB,wBAAgB,gBAAgB,IAAI,MAAM,CAazC;AAQD,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAMzD;AAUD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIvD;AAWD,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,wBAAwB,EAC/B,WAAW,SAAI,GACd,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,CAAC,CAaxD"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { USER_CODE_CHARSET, USER_CODE_GROUP_SIZE, USER_CODE_LENGTH, } from './store.js';
|
|
2
|
+
export function generateUserCode() {
|
|
3
|
+
const charset = USER_CODE_CHARSET;
|
|
4
|
+
const limit = 256 - (256 % charset.length);
|
|
5
|
+
let code = '';
|
|
6
|
+
const buffer = new Uint8Array(1);
|
|
7
|
+
while (code.length < USER_CODE_LENGTH) {
|
|
8
|
+
crypto.getRandomValues(buffer);
|
|
9
|
+
const byte = buffer[0];
|
|
10
|
+
if (byte >= limit)
|
|
11
|
+
continue;
|
|
12
|
+
code += charset[byte % charset.length];
|
|
13
|
+
}
|
|
14
|
+
return formatUserCode(code);
|
|
15
|
+
}
|
|
16
|
+
export function formatUserCode(normalized) {
|
|
17
|
+
const groups = [];
|
|
18
|
+
for (let i = 0; i < normalized.length; i += USER_CODE_GROUP_SIZE) {
|
|
19
|
+
groups.push(normalized.slice(i, i + USER_CODE_GROUP_SIZE));
|
|
20
|
+
}
|
|
21
|
+
return groups.join('-');
|
|
22
|
+
}
|
|
23
|
+
export function normalizeUserCode(input) {
|
|
24
|
+
return input
|
|
25
|
+
.toUpperCase()
|
|
26
|
+
.replace(/[\s -]/g, '');
|
|
27
|
+
}
|
|
28
|
+
export async function generateUniqueUserCode(store, maxAttempts = 5) {
|
|
29
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
30
|
+
const userCodeDisplay = generateUserCode();
|
|
31
|
+
const userCode = normalizeUserCode(userCodeDisplay);
|
|
32
|
+
const existing = await store.findByUserCode(userCode);
|
|
33
|
+
if (existing === null) {
|
|
34
|
+
return { userCode, userCodeDisplay };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
throw new Error(`Failed to generate a unique user_code after ${maxAttempts} attempts`);
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=user-code.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-code.js","sourceRoot":"","sources":["../../src/device-authorization-grant/user-code.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,GAEjB,MAAM,YAAY,CAAC;AAapB,MAAM,UAAU,gBAAgB;IAC9B,MAAM,OAAO,GAAG,iBAAiB,CAAC;IAElC,MAAM,KAAK,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IACjC,OAAO,IAAI,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;QACtC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAW,CAAC;QACjC,IAAI,IAAI,IAAI,KAAK;YAAE,SAAS;QAC5B,IAAI,IAAI,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAQD,MAAM,UAAU,cAAc,CAAC,UAAkB;IAC/C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,IAAI,oBAAoB,EAAE,CAAC;QACjE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,oBAAoB,CAAC,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC;AAUD,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,OAAO,KAAK;SACT,WAAW,EAAE;SACb,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;AAC5B,CAAC;AAWD,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,KAA+B,EAC/B,WAAW,GAAG,CAAC;IAEf,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,MAAM,eAAe,GAAG,gBAAgB,EAAE,CAAC;QAC3C,MAAM,QAAQ,GAAG,iBAAiB,CAAC,eAAe,CAAC,CAAC;QACpD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QACtD,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC;QACvC,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CACb,+CAA+C,WAAW,WAAW,CACtE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { DeviceAuthorizationRecord, DeviceAuthorizationStore } from './store.js';
|
|
2
|
+
export declare const INVALID_USER_CODE_MESSAGE = "The code is invalid or has expired";
|
|
3
|
+
export declare function findPendingRecordByUserCode(userCode: string, store: DeviceAuthorizationStore, now?: Date): Promise<DeviceAuthorizationRecord | null>;
|
|
4
|
+
export declare function issueVerificationBinding(record: DeviceAuthorizationRecord, store: DeviceAuthorizationStore): Promise<{
|
|
5
|
+
bindingSecret: string;
|
|
6
|
+
csrfToken: string;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function validateVerificationBinding(record: DeviceAuthorizationRecord, bindingSecret: string | null | undefined): Promise<void>;
|
|
9
|
+
export declare function validateVerificationCsrfToken(record: DeviceAuthorizationRecord, csrfToken: string): void;
|
|
10
|
+
export declare function recordDeviceLoginFailure(record: DeviceAuthorizationRecord, store: DeviceAuthorizationStore, maxLoginAttempts: number): Promise<{
|
|
11
|
+
canRetry: boolean;
|
|
12
|
+
remainingAttempts: number;
|
|
13
|
+
}>;
|
|
14
|
+
export declare function approveDeviceAuthorization(input: {
|
|
15
|
+
record: DeviceAuthorizationRecord;
|
|
16
|
+
store: DeviceAuthorizationStore;
|
|
17
|
+
csrfToken: string;
|
|
18
|
+
subject: string;
|
|
19
|
+
authTime: number;
|
|
20
|
+
}): Promise<DeviceAuthorizationRecord>;
|
|
21
|
+
export declare function denyDeviceAuthorization(input: {
|
|
22
|
+
record: DeviceAuthorizationRecord;
|
|
23
|
+
store: DeviceAuthorizationStore;
|
|
24
|
+
csrfToken: string;
|
|
25
|
+
}): Promise<DeviceAuthorizationRecord>;
|
|
26
|
+
//# sourceMappingURL=verification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verification.d.ts","sourceRoot":"","sources":["../../src/device-authorization-grant/verification.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EACV,yBAAyB,EACzB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AAWpB,eAAO,MAAM,yBAAyB,uCAAuC,CAAC;AA0B9E,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,wBAAwB,EAC/B,GAAG,GAAE,IAAiB,GACrB,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAQ3C;AAcD,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,yBAAyB,EACjC,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAOvD;AAcD,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,yBAAyB,EACjC,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACvC,OAAO,CAAC,IAAI,CAAC,CAQf;AAYD,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,yBAAyB,EACjC,SAAS,EAAE,MAAM,GAChB,IAAI,CAIN;AAcD,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,yBAAyB,EACjC,KAAK,EAAE,wBAAwB,EAC/B,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,CAAC,CAW3D;AAeD,wBAAsB,0BAA0B,CAAC,KAAK,EAAE;IACtD,MAAM,EAAE,yBAAyB,CAAC;IAClC,KAAK,EAAE,wBAAwB,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAerC;AAQD,wBAAsB,uBAAuB,CAAC,KAAK,EAAE;IACnD,MAAM,EAAE,yBAAyB,CAAC;IAClC,KAAK,EAAE,wBAAwB,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,yBAAyB,CAAC,CASrC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { generateRandomString } from '@maronn-openid-connect/core';
|
|
2
|
+
import { DeviceAuthorizationError, DeviceVerificationError } from './errors.js';
|
|
3
|
+
import { normalizeUserCode } from './user-code.js';
|
|
4
|
+
const VERIFICATION_SECRET_BYTE_LENGTH = 32;
|
|
5
|
+
export const INVALID_USER_CODE_MESSAGE = 'The code is invalid or has expired';
|
|
6
|
+
async function sha256Base64Url(value) {
|
|
7
|
+
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(value));
|
|
8
|
+
let binary = '';
|
|
9
|
+
for (const byte of new Uint8Array(digest)) {
|
|
10
|
+
binary += String.fromCharCode(byte);
|
|
11
|
+
}
|
|
12
|
+
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
13
|
+
}
|
|
14
|
+
export async function findPendingRecordByUserCode(userCode, store, now = new Date()) {
|
|
15
|
+
const normalized = normalizeUserCode(userCode);
|
|
16
|
+
if (normalized === '')
|
|
17
|
+
return null;
|
|
18
|
+
const record = await store.findByUserCode(normalized);
|
|
19
|
+
if (record === null)
|
|
20
|
+
return null;
|
|
21
|
+
if (record.status !== 'pending')
|
|
22
|
+
return null;
|
|
23
|
+
if (now.getTime() >= record.expiresAt.getTime())
|
|
24
|
+
return null;
|
|
25
|
+
return record;
|
|
26
|
+
}
|
|
27
|
+
export async function issueVerificationBinding(record, store) {
|
|
28
|
+
const bindingSecret = generateRandomString(VERIFICATION_SECRET_BYTE_LENGTH);
|
|
29
|
+
const csrfToken = generateRandomString(VERIFICATION_SECRET_BYTE_LENGTH);
|
|
30
|
+
record.bindingHash = await sha256Base64Url(bindingSecret);
|
|
31
|
+
record.csrfToken = csrfToken;
|
|
32
|
+
await store.update(record);
|
|
33
|
+
return { bindingSecret, csrfToken };
|
|
34
|
+
}
|
|
35
|
+
export async function validateVerificationBinding(record, bindingSecret) {
|
|
36
|
+
if (record.bindingHash === null || !bindingSecret) {
|
|
37
|
+
throw new DeviceVerificationError('Device verification binding is missing', 403);
|
|
38
|
+
}
|
|
39
|
+
const presented = await sha256Base64Url(bindingSecret);
|
|
40
|
+
if (presented !== record.bindingHash) {
|
|
41
|
+
throw new DeviceVerificationError('Device verification binding is invalid', 403);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function validateVerificationCsrfToken(record, csrfToken) {
|
|
45
|
+
if (record.csrfToken === null || csrfToken === '' || csrfToken !== record.csrfToken) {
|
|
46
|
+
throw new DeviceVerificationError('CSRF token mismatch', 403);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export async function recordDeviceLoginFailure(record, store, maxLoginAttempts) {
|
|
50
|
+
record.loginAttempts += 1;
|
|
51
|
+
const canRetry = record.loginAttempts < maxLoginAttempts;
|
|
52
|
+
if (!canRetry) {
|
|
53
|
+
record.status = 'denied';
|
|
54
|
+
}
|
|
55
|
+
await store.update(record);
|
|
56
|
+
return {
|
|
57
|
+
canRetry,
|
|
58
|
+
remainingAttempts: Math.max(0, maxLoginAttempts - record.loginAttempts),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export async function approveDeviceAuthorization(input) {
|
|
62
|
+
validateVerificationCsrfToken(input.record, input.csrfToken);
|
|
63
|
+
assertPending(input.record);
|
|
64
|
+
input.record.status = 'approved';
|
|
65
|
+
input.record.subject = input.subject;
|
|
66
|
+
input.record.authTime = input.authTime;
|
|
67
|
+
input.record.approvedScope = [...input.record.scope];
|
|
68
|
+
input.record.grantId = generateRandomString(VERIFICATION_SECRET_BYTE_LENGTH);
|
|
69
|
+
input.record.bindingHash = null;
|
|
70
|
+
input.record.csrfToken = null;
|
|
71
|
+
await input.store.update(input.record);
|
|
72
|
+
return input.record;
|
|
73
|
+
}
|
|
74
|
+
export async function denyDeviceAuthorization(input) {
|
|
75
|
+
validateVerificationCsrfToken(input.record, input.csrfToken);
|
|
76
|
+
assertPending(input.record);
|
|
77
|
+
input.record.status = 'denied';
|
|
78
|
+
input.record.bindingHash = null;
|
|
79
|
+
input.record.csrfToken = null;
|
|
80
|
+
await input.store.update(input.record);
|
|
81
|
+
return input.record;
|
|
82
|
+
}
|
|
83
|
+
function assertPending(record) {
|
|
84
|
+
if (record.status !== 'pending') {
|
|
85
|
+
throw new DeviceAuthorizationError('invalid_grant', INVALID_USER_CODE_MESSAGE);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=verification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verification.js","sourceRoot":"","sources":["../../src/device-authorization-grant/verification.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAOnD,MAAM,+BAA+B,GAAG,EAAE,CAAC;AAQ3C,MAAM,CAAC,MAAM,yBAAyB,GAAG,oCAAoC,CAAC;AAQ9E,KAAK,UAAU,eAAe,CAAC,KAAa;IAC1C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtF,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,IAAI,IAAI,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACjF,CAAC;AAWD,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,QAAgB,EAChB,KAA+B,EAC/B,MAAY,IAAI,IAAI,EAAE;IAEtB,MAAM,UAAU,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC/C,IAAI,UAAU,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IACtD,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAC7C,IAAI,GAAG,CAAC,OAAO,EAAE,IAAI,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE;QAAE,OAAO,IAAI,CAAC;IAC7D,OAAO,MAAM,CAAC;AAChB,CAAC;AAcD,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,MAAiC,EACjC,KAA+B;IAE/B,MAAM,aAAa,GAAG,oBAAoB,CAAC,+BAA+B,CAAC,CAAC;IAC5E,MAAM,SAAS,GAAG,oBAAoB,CAAC,+BAA+B,CAAC,CAAC;IACxE,MAAM,CAAC,WAAW,GAAG,MAAM,eAAe,CAAC,aAAa,CAAC,CAAC;IAC1D,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,MAAM,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC3B,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,CAAC;AACtC,CAAC;AAcD,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,MAAiC,EACjC,aAAwC;IAExC,IAAI,MAAM,CAAC,WAAW,KAAK,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QAClD,MAAM,IAAI,uBAAuB,CAAC,wCAAwC,EAAE,GAAG,CAAC,CAAC;IACnF,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,aAAa,CAAC,CAAC;IACvD,IAAI,SAAS,KAAK,MAAM,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,IAAI,uBAAuB,CAAC,wCAAwC,EAAE,GAAG,CAAC,CAAC;IACnF,CAAC;AACH,CAAC;AAYD,MAAM,UAAU,6BAA6B,CAC3C,MAAiC,EACjC,SAAiB;IAEjB,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,EAAE,IAAI,SAAS,KAAK,MAAM,CAAC,SAAS,EAAE,CAAC;QACpF,MAAM,IAAI,uBAAuB,CAAC,qBAAqB,EAAE,GAAG,CAAC,CAAC;IAChE,CAAC;AACH,CAAC;AAcD,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,MAAiC,EACjC,KAA+B,EAC/B,gBAAwB;IAExB,MAAM,CAAC,aAAa,IAAI,CAAC,CAAC;IAC1B,MAAM,QAAQ,GAAG,MAAM,CAAC,aAAa,GAAG,gBAAgB,CAAC;IACzD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,CAAC,MAAM,GAAG,QAAQ,CAAC;IAC3B,CAAC;IACD,MAAM,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC3B,OAAO;QACL,QAAQ;QACR,iBAAiB,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAAC,aAAa,CAAC;KACxE,CAAC;AACJ,CAAC;AAeD,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,KAMhD;IACC,6BAA6B,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC7D,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAE5B,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,UAAU,CAAC;IACjC,KAAK,CAAC,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IACrC,KAAK,CAAC,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IACvC,KAAK,CAAC,MAAM,CAAC,aAAa,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACrD,KAAK,CAAC,MAAM,CAAC,OAAO,GAAG,oBAAoB,CAAC,+BAA+B,CAAC,CAAC;IAG7E,KAAK,CAAC,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC;IAChC,KAAK,CAAC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;IAC9B,MAAM,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACvC,OAAO,KAAK,CAAC,MAAM,CAAC;AACtB,CAAC;AAQD,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,KAI7C;IACC,6BAA6B,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC7D,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAE5B,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,QAAQ,CAAC;IAC/B,KAAK,CAAC,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC;IAChC,KAAK,CAAC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;IAC9B,MAAM,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACvC,OAAO,KAAK,CAAC,MAAM,CAAC;AACtB,CAAC;AAMD,SAAS,aAAa,CAAC,MAAiC;IACtD,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChC,MAAM,IAAI,wBAAwB,CAChC,eAAe,EACf,yBAAyB,CAC1B,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { JARM_RESPONSE_PARAM, JARM_SUPPORTED_RESPONSE_MODES, resolveJarmResponseMode, type JarmResponseModeResolution, } from './response-mode.js';
|
|
2
|
+
export { assertJarmLifetimeSeconds, buildJarmRedirectUrl, createJarmResponseJwt, } from './response-jwt.js';
|
|
3
|
+
export type JarmAuthTransactionFields = {
|
|
4
|
+
jarmResponseMode?: 'query.jwt';
|
|
5
|
+
};
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/jarm/index.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,mBAAmB,EACnB,6BAA6B,EAC7B,uBAAuB,EACvB,KAAK,0BAA0B,GAChC,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,yBAAyB,EACzB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAa3B,MAAM,MAAM,yBAAyB,GAAG;IAEtC,gBAAgB,CAAC,EAAE,WAAW,CAAC;CAChC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/jarm/index.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,mBAAmB,EACnB,6BAA6B,EAC7B,uBAAuB,GAExB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,yBAAyB,EACzB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SigningKey } from '@maronn-openid-connect/core';
|
|
2
|
+
export declare function assertJarmLifetimeSeconds(value: number): void;
|
|
3
|
+
export declare function createJarmResponseJwt(options: {
|
|
4
|
+
issuer: string;
|
|
5
|
+
clientId: string;
|
|
6
|
+
parameters: Record<string, string | undefined>;
|
|
7
|
+
signingKey: SigningKey;
|
|
8
|
+
lifetimeSeconds?: number;
|
|
9
|
+
now?: Date;
|
|
10
|
+
}): Promise<string>;
|
|
11
|
+
export declare function buildJarmRedirectUrl(redirectUri: string, responseJwt: string): string;
|
|
12
|
+
//# sourceMappingURL=response-jwt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-jwt.d.ts","sourceRoot":"","sources":["../../src/jarm/response-jwt.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAwD9D,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAU7D;AA0BD,wBAAsB,qBAAqB,CAAC,OAAO,EAAE;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC/C,UAAU,EAAE,UAAU,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BlB;AAQD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAIrF"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const MIN_LIFETIME_SECONDS = 5;
|
|
2
|
+
const MAX_LIFETIME_SECONDS = 600;
|
|
3
|
+
const DEFAULT_LIFETIME_SECONDS = 60;
|
|
4
|
+
const RESPONSE_SIGNING_ALG = 'RS256';
|
|
5
|
+
const WEB_CRYPTO_ALGORITHM = 'RSASSA-PKCS1-v1_5';
|
|
6
|
+
function base64UrlFromBytes(bytes) {
|
|
7
|
+
let binary = '';
|
|
8
|
+
for (const byte of bytes) {
|
|
9
|
+
binary += String.fromCharCode(byte);
|
|
10
|
+
}
|
|
11
|
+
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
12
|
+
}
|
|
13
|
+
function base64UrlFromJson(value) {
|
|
14
|
+
return base64UrlFromBytes(new TextEncoder().encode(JSON.stringify(value)));
|
|
15
|
+
}
|
|
16
|
+
export function assertJarmLifetimeSeconds(value) {
|
|
17
|
+
if (!Number.isInteger(value) ||
|
|
18
|
+
value < MIN_LIFETIME_SECONDS ||
|
|
19
|
+
value > MAX_LIFETIME_SECONDS) {
|
|
20
|
+
throw new Error(`jarmConfig.jarmResponseLifetimeSeconds must be an integer between ${MIN_LIFETIME_SECONDS} and ${MAX_LIFETIME_SECONDS} seconds (JARM Section 2.1), got ${value}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export async function createJarmResponseJwt(options) {
|
|
24
|
+
const lifetimeSeconds = options.lifetimeSeconds ?? DEFAULT_LIFETIME_SECONDS;
|
|
25
|
+
const issuedAtSeconds = Math.floor((options.now ?? new Date()).getTime() / 1000);
|
|
26
|
+
const claims = {};
|
|
27
|
+
for (const [name, value] of Object.entries(options.parameters)) {
|
|
28
|
+
if (value !== undefined) {
|
|
29
|
+
claims[name] = value;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
claims['iss'] = options.issuer;
|
|
33
|
+
claims['aud'] = options.clientId;
|
|
34
|
+
claims['exp'] = issuedAtSeconds + lifetimeSeconds;
|
|
35
|
+
const encodedHeader = base64UrlFromJson({
|
|
36
|
+
alg: RESPONSE_SIGNING_ALG,
|
|
37
|
+
kid: options.signingKey.keyId,
|
|
38
|
+
});
|
|
39
|
+
const encodedPayload = base64UrlFromJson(claims);
|
|
40
|
+
const signingInput = `${encodedHeader}.${encodedPayload}`;
|
|
41
|
+
const signature = await crypto.subtle.sign(WEB_CRYPTO_ALGORITHM, options.signingKey.privateKey, new TextEncoder().encode(signingInput));
|
|
42
|
+
return `${signingInput}.${base64UrlFromBytes(new Uint8Array(signature))}`;
|
|
43
|
+
}
|
|
44
|
+
export function buildJarmRedirectUrl(redirectUri, responseJwt) {
|
|
45
|
+
const url = new URL(redirectUri);
|
|
46
|
+
url.searchParams.set('response', responseJwt);
|
|
47
|
+
return url.toString();
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=response-jwt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-jwt.js","sourceRoot":"","sources":["../../src/jarm/response-jwt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const JARM_SUPPORTED_RESPONSE_MODES: readonly ["query.jwt", "jwt"];
|
|
2
|
+
export declare const JARM_RESPONSE_PARAM = "response";
|
|
3
|
+
export type JarmResponseModeResolution = {
|
|
4
|
+
kind: 'jarm';
|
|
5
|
+
mode: 'query.jwt';
|
|
6
|
+
} | {
|
|
7
|
+
kind: 'plain';
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'unsupported-jwt-mode';
|
|
10
|
+
requested: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function resolveJarmResponseMode(params: object): JarmResponseModeResolution;
|
|
13
|
+
//# sourceMappingURL=response-mode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-mode.d.ts","sourceRoot":"","sources":["../../src/jarm/response-mode.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,6BAA6B,+BAAgC,CAAC;AAG3E,eAAO,MAAM,mBAAmB,aAAa,CAAC;AAU9C,MAAM,MAAM,0BAA0B,GAElC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GAEnC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GAEjB;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAkBxD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,0BAA0B,CAgBlF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const JARM_SUPPORTED_RESPONSE_MODES = ['query.jwt', 'jwt'];
|
|
2
|
+
export const JARM_RESPONSE_PARAM = 'response';
|
|
3
|
+
export function resolveJarmResponseMode(params) {
|
|
4
|
+
const responseMode = params['response_mode'];
|
|
5
|
+
if (typeof responseMode !== 'string') {
|
|
6
|
+
return { kind: 'plain' };
|
|
7
|
+
}
|
|
8
|
+
if (JARM_SUPPORTED_RESPONSE_MODES.includes(responseMode)) {
|
|
9
|
+
return { kind: 'jarm', mode: 'query.jwt' };
|
|
10
|
+
}
|
|
11
|
+
if (responseMode.endsWith('.jwt')) {
|
|
12
|
+
return { kind: 'unsupported-jwt-mode', requested: responseMode };
|
|
13
|
+
}
|
|
14
|
+
return { kind: 'plain' };
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=response-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-mode.js","sourceRoot":"","sources":["../../src/jarm/response-mode.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,WAAW,EAAE,KAAK,CAAU,CAAC;AAG3E,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAAC;AAkC9C,MAAM,UAAU,uBAAuB,CAAC,MAAc;IAKpD,MAAM,YAAY,GAAI,MAAsC,CAAC,eAAe,CAAC,CAAC;IAC9E,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;QACrC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAC3B,CAAC;IACD,IAAK,6BAAmD,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QAChF,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAC7C,CAAC;IACD,IAAI,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAClC,OAAO,EAAE,IAAI,EAAE,sBAAsB,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;IACnE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC3B,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { SUBJECT_TOKEN_INVALID_DESCRIPTION, TOKEN_EXCHANGE_GRANT_TYPE, TOKEN_TYPE_ACCESS_TOKEN, TokenExchangeError, authorizeTokenExchangeClient, buildTokenExchangeResponse, computeExchangedTokenLifetime, parseTokenExchangeParams, processTokenExchangeRequest, resolveExchangeTarget, resolveSubjectToken, validateExchangeScope, type ParsedTokenExchangeParams, type TokenExchangeErrorCode, type TokenExchangeGrant, type TokenExchangeRequestContext, type TokenExchangeResponse, } from './token-exchange-request.js';
|
|
1
|
+
export { ACTOR_TOKEN_INVALID_DESCRIPTION, SUBJECT_TOKEN_INVALID_DESCRIPTION, TOKEN_EXCHANGE_GRANT_TYPE, TOKEN_TYPE_ACCESS_TOKEN, TokenExchangeError, authorizeTokenExchangeClient, buildTokenExchangeResponse, composeActClaim, computeExchangedTokenLifetime, parseTokenExchangeParams, processTokenExchangeRequest, resolveActorToken, resolveExchangeTarget, resolveSubjectToken, validateExchangeScope, type ExchangedAccessTokenInfo, type ParsedTokenExchangeParams, type TokenExchangeActor, type TokenExchangeErrorCode, type TokenExchangeGrant, type TokenExchangeRequestContext, type TokenExchangeResponse, } from './token-exchange-request.js';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/token-exchange/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/token-exchange/index.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,+BAA+B,EAC/B,iCAAiC,EACjC,yBAAyB,EACzB,uBAAuB,EACvB,kBAAkB,EAClB,4BAA4B,EAC5B,0BAA0B,EAC1B,eAAe,EACf,6BAA6B,EAC7B,wBAAwB,EACxB,2BAA2B,EAC3B,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,2BAA2B,EAChC,KAAK,qBAAqB,GAC3B,MAAM,6BAA6B,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { SUBJECT_TOKEN_INVALID_DESCRIPTION, TOKEN_EXCHANGE_GRANT_TYPE, TOKEN_TYPE_ACCESS_TOKEN, TokenExchangeError, authorizeTokenExchangeClient, buildTokenExchangeResponse, computeExchangedTokenLifetime, parseTokenExchangeParams, processTokenExchangeRequest, resolveExchangeTarget, resolveSubjectToken, validateExchangeScope, } from './token-exchange-request.js';
|
|
1
|
+
export { ACTOR_TOKEN_INVALID_DESCRIPTION, SUBJECT_TOKEN_INVALID_DESCRIPTION, TOKEN_EXCHANGE_GRANT_TYPE, TOKEN_TYPE_ACCESS_TOKEN, TokenExchangeError, authorizeTokenExchangeClient, buildTokenExchangeResponse, composeActClaim, computeExchangedTokenLifetime, parseTokenExchangeParams, processTokenExchangeRequest, resolveActorToken, resolveExchangeTarget, resolveSubjectToken, validateExchangeScope, } from './token-exchange-request.js';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/token-exchange/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/token-exchange/index.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,+BAA+B,EAC/B,iCAAiC,EACjC,yBAAyB,EACzB,uBAAuB,EACvB,kBAAkB,EAClB,4BAA4B,EAC5B,0BAA0B,EAC1B,eAAe,EACf,6BAA6B,EAC7B,wBAAwB,EACxB,2BAA2B,EAC3B,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACnB,qBAAqB,GAQtB,MAAM,6BAA6B,CAAC"}
|
|
@@ -2,6 +2,7 @@ import { type AccessTokenInfo, type AccessTokenResolver, type TokenClientInfo }
|
|
|
2
2
|
export declare const TOKEN_EXCHANGE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange";
|
|
3
3
|
export declare const TOKEN_TYPE_ACCESS_TOKEN = "urn:ietf:params:oauth:token-type:access_token";
|
|
4
4
|
export declare const SUBJECT_TOKEN_INVALID_DESCRIPTION = "The provided subject_token is not valid";
|
|
5
|
+
export declare const ACTOR_TOKEN_INVALID_DESCRIPTION = "The provided actor_token is not valid";
|
|
5
6
|
export type TokenExchangeErrorCode = 'invalid_request' | 'unauthorized_client' | 'invalid_scope' | 'invalid_target';
|
|
6
7
|
export declare class TokenExchangeError extends Error {
|
|
7
8
|
readonly code: TokenExchangeErrorCode;
|
|
@@ -9,11 +10,19 @@ export declare class TokenExchangeError extends Error {
|
|
|
9
10
|
constructor(code: TokenExchangeErrorCode, errorDescription: string);
|
|
10
11
|
get statusCode(): 400;
|
|
11
12
|
}
|
|
13
|
+
export interface TokenExchangeActor {
|
|
14
|
+
sub: string;
|
|
15
|
+
act?: TokenExchangeActor;
|
|
16
|
+
}
|
|
17
|
+
export type ExchangedAccessTokenInfo = AccessTokenInfo & {
|
|
18
|
+
act?: TokenExchangeActor;
|
|
19
|
+
};
|
|
12
20
|
export interface ParsedTokenExchangeParams {
|
|
13
21
|
subjectToken: string;
|
|
14
22
|
scope?: string;
|
|
15
23
|
audience?: string;
|
|
16
24
|
resource?: string;
|
|
25
|
+
actorToken?: string;
|
|
17
26
|
}
|
|
18
27
|
export interface TokenExchangeGrant {
|
|
19
28
|
subject: string;
|
|
@@ -22,6 +31,7 @@ export interface TokenExchangeGrant {
|
|
|
22
31
|
requestedAudience?: string[];
|
|
23
32
|
expiresIn: number;
|
|
24
33
|
grantId?: string;
|
|
34
|
+
actor?: TokenExchangeActor;
|
|
25
35
|
}
|
|
26
36
|
export interface TokenExchangeResponse {
|
|
27
37
|
access_token: string;
|
|
@@ -45,6 +55,15 @@ export declare function resolveSubjectToken(options: {
|
|
|
45
55
|
accessTokenResolver: AccessTokenResolver;
|
|
46
56
|
now?: Date;
|
|
47
57
|
}): Promise<AccessTokenInfo>;
|
|
58
|
+
export declare function resolveActorToken(options: {
|
|
59
|
+
actorToken: string;
|
|
60
|
+
accessTokenResolver: AccessTokenResolver;
|
|
61
|
+
now?: Date;
|
|
62
|
+
}): Promise<AccessTokenInfo>;
|
|
63
|
+
export declare function composeActClaim(options: {
|
|
64
|
+
actorSub: string;
|
|
65
|
+
subjectActChain?: TokenExchangeActor;
|
|
66
|
+
}): TokenExchangeActor;
|
|
48
67
|
export declare function validateExchangeScope(requestedScope: string | undefined, subjectScope: string[]): string[];
|
|
49
68
|
export declare function resolveExchangeTarget(options: {
|
|
50
69
|
audience?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-exchange-request.d.ts","sourceRoot":"","sources":["../../src/token-exchange/token-exchange-request.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"token-exchange-request.d.ts","sourceRoot":"","sources":["../../src/token-exchange/token-exchange-request.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { sanitizeErrorDescription, } from '@maronn-openid-connect/core';
|
|
|
2
2
|
export const TOKEN_EXCHANGE_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:token-exchange';
|
|
3
3
|
export const TOKEN_TYPE_ACCESS_TOKEN = 'urn:ietf:params:oauth:token-type:access_token';
|
|
4
4
|
export const SUBJECT_TOKEN_INVALID_DESCRIPTION = 'The provided subject_token is not valid';
|
|
5
|
+
export const ACTOR_TOKEN_INVALID_DESCRIPTION = 'The provided actor_token is not valid';
|
|
5
6
|
export class TokenExchangeError extends Error {
|
|
6
7
|
code;
|
|
7
8
|
errorDescription;
|
|
@@ -26,9 +27,6 @@ export function authorizeTokenExchangeClient(client) {
|
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
29
|
export function parseTokenExchangeParams(params) {
|
|
29
|
-
if (params['actor_token'] !== undefined || params['actor_token_type'] !== undefined) {
|
|
30
|
-
throw new TokenExchangeError('invalid_request', 'Delegation is not supported: actor_token and actor_token_type must not be present.');
|
|
31
|
-
}
|
|
32
30
|
const subjectToken = optional(params['subject_token']);
|
|
33
31
|
if (subjectToken === undefined) {
|
|
34
32
|
throw new TokenExchangeError('invalid_request', 'subject_token is required');
|
|
@@ -48,26 +46,36 @@ export function parseTokenExchangeParams(params) {
|
|
|
48
46
|
if (resource !== undefined && !isAbsoluteUriWithoutFragment(resource)) {
|
|
49
47
|
throw new TokenExchangeError('invalid_request', 'resource must be an absolute URI without a fragment component');
|
|
50
48
|
}
|
|
49
|
+
const actorToken = optional(params['actor_token']);
|
|
50
|
+
const actorTokenType = optional(params['actor_token_type']);
|
|
51
|
+
if (actorToken !== undefined && actorTokenType === undefined) {
|
|
52
|
+
throw new TokenExchangeError('invalid_request', 'actor_token_type is required when actor_token is present');
|
|
53
|
+
}
|
|
54
|
+
if (actorToken === undefined && actorTokenType !== undefined) {
|
|
55
|
+
throw new TokenExchangeError('invalid_request', 'actor_token_type must not be present without actor_token');
|
|
56
|
+
}
|
|
57
|
+
if (actorTokenType !== undefined && actorTokenType !== TOKEN_TYPE_ACCESS_TOKEN) {
|
|
58
|
+
throw new TokenExchangeError('invalid_request', `Unsupported actor_token_type. Only ${TOKEN_TYPE_ACCESS_TOKEN} is supported.`);
|
|
59
|
+
}
|
|
51
60
|
return {
|
|
52
61
|
subjectToken,
|
|
53
62
|
scope: optional(params['scope']),
|
|
54
63
|
audience: optional(params['audience']),
|
|
55
64
|
resource,
|
|
65
|
+
actorToken,
|
|
56
66
|
};
|
|
57
67
|
}
|
|
58
68
|
export async function resolveSubjectToken(options) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (info.nbf !== undefined && info.nbf > nowSeconds) {
|
|
68
|
-
throw invalidSubjectToken();
|
|
69
|
+
return resolveExchangeToken(options.subjectToken, options.accessTokenResolver, options.now, invalidSubjectToken);
|
|
70
|
+
}
|
|
71
|
+
export async function resolveActorToken(options) {
|
|
72
|
+
return resolveExchangeToken(options.actorToken, options.accessTokenResolver, options.now, invalidActorToken);
|
|
73
|
+
}
|
|
74
|
+
export function composeActClaim(options) {
|
|
75
|
+
if (options.subjectActChain === undefined) {
|
|
76
|
+
return { sub: options.actorSub };
|
|
69
77
|
}
|
|
70
|
-
return
|
|
78
|
+
return { sub: options.actorSub, act: options.subjectActChain };
|
|
71
79
|
}
|
|
72
80
|
export function validateExchangeScope(requestedScope, subjectScope) {
|
|
73
81
|
const requested = splitScope(requestedScope);
|
|
@@ -125,6 +133,18 @@ export async function processTokenExchangeRequest(context) {
|
|
|
125
133
|
accessTokenResolver: context.accessTokenResolver,
|
|
126
134
|
now: context.now,
|
|
127
135
|
});
|
|
136
|
+
let actor;
|
|
137
|
+
if (parsed.actorToken !== undefined) {
|
|
138
|
+
const actorInfo = await resolveActorToken({
|
|
139
|
+
actorToken: parsed.actorToken,
|
|
140
|
+
accessTokenResolver: context.accessTokenResolver,
|
|
141
|
+
now: context.now,
|
|
142
|
+
});
|
|
143
|
+
actor = composeActClaim({
|
|
144
|
+
actorSub: actorInfo.sub,
|
|
145
|
+
subjectActChain: subject.act,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
128
148
|
const scope = validateExchangeScope(parsed.scope, subject.scope);
|
|
129
149
|
const requestedAudience = resolveExchangeTarget({
|
|
130
150
|
audience: parsed.audience,
|
|
@@ -144,6 +164,7 @@ export async function processTokenExchangeRequest(context) {
|
|
|
144
164
|
requestedAudience,
|
|
145
165
|
expiresIn,
|
|
146
166
|
grantId: subject.grantId,
|
|
167
|
+
...(actor === undefined ? {} : { actor }),
|
|
147
168
|
};
|
|
148
169
|
}
|
|
149
170
|
function optional(value) {
|
|
@@ -163,6 +184,23 @@ function toEpochSeconds(now) {
|
|
|
163
184
|
function invalidSubjectToken() {
|
|
164
185
|
return new TokenExchangeError('invalid_request', SUBJECT_TOKEN_INVALID_DESCRIPTION);
|
|
165
186
|
}
|
|
187
|
+
function invalidActorToken() {
|
|
188
|
+
return new TokenExchangeError('invalid_request', ACTOR_TOKEN_INVALID_DESCRIPTION);
|
|
189
|
+
}
|
|
190
|
+
async function resolveExchangeToken(token, accessTokenResolver, now, invalidToken) {
|
|
191
|
+
const info = await accessTokenResolver.findAccessToken(token);
|
|
192
|
+
if (info === null) {
|
|
193
|
+
throw invalidToken();
|
|
194
|
+
}
|
|
195
|
+
const nowSeconds = toEpochSeconds(now);
|
|
196
|
+
if (info.expiresAt <= nowSeconds) {
|
|
197
|
+
throw invalidToken();
|
|
198
|
+
}
|
|
199
|
+
if (info.nbf !== undefined && info.nbf > nowSeconds) {
|
|
200
|
+
throw invalidToken();
|
|
201
|
+
}
|
|
202
|
+
return info;
|
|
203
|
+
}
|
|
166
204
|
function isAbsoluteUriWithoutFragment(value) {
|
|
167
205
|
if (value.includes('#'))
|
|
168
206
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-exchange-request.js","sourceRoot":"","sources":["../../src/token-exchange/token-exchange-request.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"token-exchange-request.js","sourceRoot":"","sources":["../../src/token-exchange/token-exchange-request.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maronn-openid-connect/experimental",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Experimental OAuth/OIDC extensions for maronn-openid-connect (unstable APIs)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
|
+
"./device-authorization-grant": {
|
|
8
|
+
"types": "./dist/device-authorization-grant/index.d.ts",
|
|
9
|
+
"import": "./dist/device-authorization-grant/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./jarm": {
|
|
12
|
+
"types": "./dist/jarm/index.d.ts",
|
|
13
|
+
"import": "./dist/jarm/index.js"
|
|
14
|
+
},
|
|
7
15
|
"./par": {
|
|
8
16
|
"types": "./dist/par/index.d.ts",
|
|
9
17
|
"import": "./dist/par/index.js"
|