@maronn-openid-connect/experimental 0.0.3 → 0.0.4
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 +2 -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/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
|
|
|
@@ -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":"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"}
|
|
@@ -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"}
|
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.4",
|
|
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"
|