@atproto/oauth-types 0.1.3 → 0.1.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/CHANGELOG.md +36 -0
- package/dist/atproto-loopback-client-metadata.d.ts.map +1 -1
- package/dist/atproto-loopback-client-metadata.js +5 -17
- package/dist/atproto-loopback-client-metadata.js.map +1 -1
- package/dist/index.d.ts +18 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -5
- package/dist/index.js.map +1 -1
- package/dist/oauth-access-token.d.ts +4 -0
- package/dist/oauth-access-token.d.ts.map +1 -0
- package/dist/oauth-access-token.js +6 -0
- package/dist/oauth-access-token.js.map +1 -0
- package/dist/oauth-authorization-code-grant-token-request.d.ts +20 -0
- package/dist/oauth-authorization-code-grant-token-request.d.ts.map +1 -0
- package/dist/oauth-authorization-code-grant-token-request.js +17 -0
- package/dist/oauth-authorization-code-grant-token-request.js.map +1 -0
- package/dist/oauth-authorization-request-jar.d.ts +16 -0
- package/dist/oauth-authorization-request-jar.d.ts.map +1 -0
- package/dist/oauth-authorization-request-jar.js +15 -0
- package/dist/oauth-authorization-request-jar.js.map +1 -0
- package/dist/oauth-authorization-request-par.d.ts +122 -0
- package/dist/oauth-authorization-request-par.d.ts.map +1 -0
- package/dist/oauth-authorization-request-par.js +11 -0
- package/dist/oauth-authorization-request-par.js.map +1 -0
- package/dist/{oauth-authentication-request-parameters.d.ts → oauth-authorization-request-parameters.d.ts} +16 -16
- package/dist/oauth-authorization-request-parameters.d.ts.map +1 -0
- package/dist/{oauth-authentication-request-parameters.js → oauth-authorization-request-parameters.js} +17 -25
- package/dist/oauth-authorization-request-parameters.js.map +1 -0
- package/dist/oauth-authorization-request-query.d.ts +128 -0
- package/dist/oauth-authorization-request-query.d.ts.map +1 -0
- package/dist/oauth-authorization-request-query.js +13 -0
- package/dist/oauth-authorization-request-query.js.map +1 -0
- package/dist/oauth-authorization-request-uri.d.ts +10 -0
- package/dist/oauth-authorization-request-uri.d.ts.map +1 -0
- package/dist/oauth-authorization-request-uri.js +9 -0
- package/dist/oauth-authorization-request-uri.js.map +1 -0
- package/dist/oauth-authorization-server-metadata.d.ts +10 -10
- package/dist/oauth-authorization-server-metadata.d.ts.map +1 -1
- package/dist/oauth-authorization-server-metadata.js +5 -1
- package/dist/oauth-authorization-server-metadata.js.map +1 -1
- package/dist/oauth-client-credentials-grant-token-request.d.ts +10 -0
- package/dist/oauth-client-credentials-grant-token-request.d.ts.map +1 -0
- package/dist/oauth-client-credentials-grant-token-request.js +8 -0
- package/dist/oauth-client-credentials-grant-token-request.js.map +1 -0
- package/dist/oauth-client-credentials.d.ts +18 -2
- package/dist/oauth-client-credentials.d.ts.map +1 -1
- package/dist/oauth-client-credentials.js +8 -2
- package/dist/oauth-client-credentials.js.map +1 -1
- package/dist/oauth-client-id-discoverable.d.ts +3 -2
- package/dist/oauth-client-id-discoverable.d.ts.map +1 -1
- package/dist/oauth-client-id-discoverable.js +21 -18
- package/dist/oauth-client-id-discoverable.js.map +1 -1
- package/dist/oauth-client-id-loopback.d.ts +10 -3
- package/dist/oauth-client-id-loopback.d.ts.map +1 -1
- package/dist/oauth-client-id-loopback.js +58 -21
- package/dist/oauth-client-id-loopback.js.map +1 -1
- package/dist/oauth-client-metadata.d.ts +1 -1
- package/dist/oauth-client-metadata.d.ts.map +1 -1
- package/dist/oauth-client-metadata.js +2 -1
- package/dist/oauth-client-metadata.js.map +1 -1
- package/dist/oauth-code-challenge-method.d.ts +3 -0
- package/dist/oauth-code-challenge-method.d.ts.map +1 -0
- package/dist/oauth-code-challenge-method.js +6 -0
- package/dist/oauth-code-challenge-method.js.map +1 -0
- package/dist/oauth-introspection-response.d.ts +20 -0
- package/dist/oauth-introspection-response.d.ts.map +1 -0
- package/dist/oauth-introspection-response.js +3 -0
- package/dist/oauth-introspection-response.js.map +1 -0
- package/dist/oauth-par-response.d.ts +3 -0
- package/dist/oauth-par-response.d.ts.map +1 -1
- package/dist/oauth-par-response.js +1 -0
- package/dist/oauth-par-response.js.map +1 -1
- package/dist/oauth-password-grant-token-request.d.ts +16 -0
- package/dist/oauth-password-grant-token-request.d.ts.map +1 -0
- package/dist/oauth-password-grant-token-request.js +10 -0
- package/dist/oauth-password-grant-token-request.js.map +1 -0
- package/dist/oauth-refresh-token-grant-token-request.d.ts +16 -0
- package/dist/oauth-refresh-token-grant-token-request.d.ts.map +1 -0
- package/dist/oauth-refresh-token-grant-token-request.js +12 -0
- package/dist/oauth-refresh-token-grant-token-request.js.map +1 -0
- package/dist/oauth-refresh-token.d.ts +4 -0
- package/dist/oauth-refresh-token.d.ts.map +1 -0
- package/dist/oauth-refresh-token.js +6 -0
- package/dist/oauth-refresh-token.js.map +1 -0
- package/dist/oauth-request-uri.d.ts +4 -0
- package/dist/oauth-request-uri.d.ts.map +1 -0
- package/dist/oauth-request-uri.js +6 -0
- package/dist/oauth-request-uri.js.map +1 -0
- package/dist/oauth-response-type.js +2 -2
- package/dist/oauth-response-type.js.map +1 -1
- package/dist/oauth-scope.d.ts +10 -0
- package/dist/oauth-scope.d.ts.map +1 -0
- package/dist/oauth-scope.js +16 -0
- package/dist/oauth-scope.js.map +1 -0
- package/dist/oauth-token-identification.d.ts +13 -0
- package/dist/oauth-token-identification.d.ts.map +1 -0
- package/dist/oauth-token-identification.js +11 -0
- package/dist/oauth-token-identification.js.map +1 -0
- package/dist/oauth-token-request.d.ts +49 -0
- package/dist/oauth-token-request.d.ts.map +1 -0
- package/dist/oauth-token-request.js +15 -0
- package/dist/oauth-token-request.js.map +1 -0
- package/dist/oauth-token-response.d.ts +0 -3
- package/dist/oauth-token-response.d.ts.map +1 -1
- package/dist/oauth-token-response.js +0 -1
- package/dist/oauth-token-response.js.map +1 -1
- package/dist/util.d.ts +2 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +34 -3
- package/dist/util.js.map +1 -1
- package/package.json +1 -1
- package/src/atproto-loopback-client-metadata.ts +9 -23
- package/src/index.ts +18 -5
- package/src/oauth-access-token.ts +4 -0
- package/src/oauth-authorization-code-grant-token-request.ts +18 -0
- package/src/oauth-authorization-request-jar.ts +16 -0
- package/src/oauth-authorization-request-par.ts +13 -0
- package/src/{oauth-authentication-request-parameters.ts → oauth-authorization-request-parameters.ts} +22 -31
- package/src/oauth-authorization-request-query.ts +15 -0
- package/src/oauth-authorization-request-uri.ts +11 -0
- package/src/oauth-authorization-server-metadata.ts +5 -1
- package/src/oauth-client-credentials-grant-token-request.ts +9 -0
- package/src/oauth-client-credentials.ts +21 -1
- package/src/oauth-client-id-discoverable.ts +29 -26
- package/src/oauth-client-id-loopback.ts +78 -30
- package/src/oauth-client-metadata.ts +2 -1
- package/src/oauth-code-challenge-method.ts +3 -0
- package/src/oauth-introspection-response.ts +23 -0
- package/src/oauth-par-response.ts +1 -0
- package/src/oauth-password-grant-token-request.ts +11 -0
- package/src/oauth-refresh-token-grant-token-request.ts +13 -0
- package/src/oauth-refresh-token.ts +4 -0
- package/src/oauth-request-uri.ts +5 -0
- package/src/oauth-response-type.ts +2 -2
- package/src/oauth-scope.ts +15 -0
- package/src/oauth-token-identification.ts +12 -0
- package/src/oauth-token-request.ts +14 -0
- package/src/oauth-token-response.ts +0 -1
- package/src/util.ts +41 -1
- package/dist/access-token.d.ts +0 -4
- package/dist/access-token.d.ts.map +0 -1
- package/dist/access-token.js +0 -6
- package/dist/access-token.js.map +0 -1
- package/dist/oauth-authentication-request-parameters.d.ts.map +0 -1
- package/dist/oauth-authentication-request-parameters.js.map +0 -1
- package/dist/oauth-client-id-url.d.ts +0 -3
- package/dist/oauth-client-id-url.d.ts.map +0 -1
- package/dist/oauth-client-id-url.js +0 -21
- package/dist/oauth-client-id-url.js.map +0 -1
- package/dist/oauth-client-identification.d.ts +0 -31
- package/dist/oauth-client-identification.d.ts.map +0 -1
- package/dist/oauth-client-identification.js +0 -12
- package/dist/oauth-client-identification.js.map +0 -1
- package/src/access-token.ts +0 -4
- package/src/oauth-client-id-url.ts +0 -25
- package/src/oauth-client-identification.ts +0 -14
package/dist/util.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,wBAAgB,
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,WAQ5C;AAED,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,WAAW,GAAG,OAAO,CAAA;AAE9D,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,YAAY,CAElE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,GAAG,OAAO,CAG1D;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,GAAG,GAAG,GAAG,IAAI,CAMvD;AAED,wBAAgB,cAAc,CAAC,GAAG,KAAA,OAsCjC"}
|
package/dist/util.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.safeUrl = exports.isLoopbackUrl = exports.isLoopbackHost = exports.
|
|
4
|
-
function
|
|
3
|
+
exports.extractUrlPath = exports.safeUrl = exports.isLoopbackUrl = exports.isLoopbackHost = exports.isHostnameIP = void 0;
|
|
4
|
+
function isHostnameIP(hostname) {
|
|
5
5
|
// IPv4
|
|
6
6
|
if (hostname.match(/^\d+\.\d+\.\d+\.\d+$/))
|
|
7
7
|
return true;
|
|
@@ -10,7 +10,7 @@ function isIP(hostname) {
|
|
|
10
10
|
return true;
|
|
11
11
|
return false;
|
|
12
12
|
}
|
|
13
|
-
exports.
|
|
13
|
+
exports.isHostnameIP = isHostnameIP;
|
|
14
14
|
function isLoopbackHost(host) {
|
|
15
15
|
return host === 'localhost' || host === '127.0.0.1' || host === '[::1]';
|
|
16
16
|
}
|
|
@@ -29,4 +29,35 @@ function safeUrl(input) {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
exports.safeUrl = safeUrl;
|
|
32
|
+
function extractUrlPath(url) {
|
|
33
|
+
// Extracts the path from a URL, without relying on the URL constructor
|
|
34
|
+
// (because it normalizes the URL)
|
|
35
|
+
const endOfProtocol = url.startsWith('https://')
|
|
36
|
+
? 8
|
|
37
|
+
: url.startsWith('http://')
|
|
38
|
+
? 7
|
|
39
|
+
: -1;
|
|
40
|
+
if (endOfProtocol === -1) {
|
|
41
|
+
throw new TypeError('URL must use the "https:" or "http:" protocol');
|
|
42
|
+
}
|
|
43
|
+
const hashIdx = url.indexOf('#', endOfProtocol);
|
|
44
|
+
const questionIdx = url.indexOf('?', endOfProtocol);
|
|
45
|
+
const queryStrIdx = questionIdx !== -1 && (hashIdx === -1 || questionIdx < hashIdx)
|
|
46
|
+
? questionIdx
|
|
47
|
+
: -1;
|
|
48
|
+
const pathEnd = hashIdx === -1
|
|
49
|
+
? queryStrIdx === -1
|
|
50
|
+
? url.length
|
|
51
|
+
: queryStrIdx
|
|
52
|
+
: queryStrIdx === -1
|
|
53
|
+
? hashIdx
|
|
54
|
+
: Math.min(hashIdx, queryStrIdx);
|
|
55
|
+
const slashIdx = url.indexOf('/', endOfProtocol);
|
|
56
|
+
const pathStart = slashIdx === -1 || slashIdx > pathEnd ? pathEnd : slashIdx;
|
|
57
|
+
if (endOfProtocol === pathStart) {
|
|
58
|
+
throw new TypeError('URL must contain a host');
|
|
59
|
+
}
|
|
60
|
+
return url.substring(pathStart, pathEnd);
|
|
61
|
+
}
|
|
62
|
+
exports.extractUrlPath = extractUrlPath;
|
|
32
63
|
//# sourceMappingURL=util.js.map
|
package/dist/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;;AAAA,SAAgB,
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;;AAAA,SAAgB,YAAY,CAAC,QAAgB;IAC3C,OAAO;IACP,IAAI,QAAQ,CAAC,KAAK,CAAC,sBAAsB,CAAC;QAAE,OAAO,IAAI,CAAA;IAEvD,OAAO;IACP,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IAEnE,OAAO,KAAK,CAAA;AACd,CAAC;AARD,oCAQC;AAID,SAAgB,cAAc,CAAC,IAAa;IAC1C,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,OAAO,CAAA;AACzE,CAAC;AAFD,wCAEC;AAED,SAAgB,aAAa,CAAC,KAAmB;IAC/C,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;IAC9D,OAAO,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;AACrC,CAAC;AAHD,sCAGC;AAED,SAAgB,OAAO,CAAC,KAAmB;IACzC,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAND,0BAMC;AAED,SAAgB,cAAc,CAAC,GAAG;IAChC,uEAAuE;IACvE,kCAAkC;IAClC,MAAM,aAAa,GAAG,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC;QAC9C,CAAC,CAAC,CAAC;QACH,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC;YACzB,CAAC,CAAC,CAAC;YACH,CAAC,CAAC,CAAC,CAAC,CAAA;IACR,IAAI,aAAa,KAAK,CAAC,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,SAAS,CAAC,+CAA+C,CAAC,CAAA;IACtE,CAAC;IAED,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,CAAA;IAC/C,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,CAAA;IAEnD,MAAM,WAAW,GACf,WAAW,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,CAAC,IAAI,WAAW,GAAG,OAAO,CAAC;QAC7D,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,CAAC,CAAC,CAAA;IAER,MAAM,OAAO,GACX,OAAO,KAAK,CAAC,CAAC;QACZ,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC;YAClB,CAAC,CAAC,GAAG,CAAC,MAAM;YACZ,CAAC,CAAC,WAAW;QACf,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC;YAClB,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;IAEtC,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,CAAA;IAEhD,MAAM,SAAS,GAAG,QAAQ,KAAK,CAAC,CAAC,IAAI,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAA;IAE5E,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,MAAM,IAAI,SAAS,CAAC,yBAAyB,CAAC,CAAA;IAChD,CAAC;IAED,OAAO,GAAG,CAAC,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;AAC1C,CAAC;AAtCD,wCAsCC"}
|
package/package.json
CHANGED
|
@@ -1,35 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parseOAuthLoopbackClientId } from './oauth-client-id-loopback.js'
|
|
2
2
|
import { OAuthClientMetadataInput } from './oauth-client-metadata.js'
|
|
3
|
-
import { parseOAuthClientIdUrl } from './oauth-client-id-url.js'
|
|
4
3
|
|
|
5
4
|
export function atprotoLoopbackClientMetadata(
|
|
6
5
|
clientId: string,
|
|
7
6
|
): OAuthClientMetadataInput {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const { origin, pathname, searchParams } = parseOAuthClientIdUrl(clientId)
|
|
13
|
-
|
|
14
|
-
for (const name of searchParams.keys()) {
|
|
15
|
-
if (name !== 'redirect_uri') {
|
|
16
|
-
throw new TypeError(`Invalid query parameter ${name} in client ID`)
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
const redirectUris = searchParams.getAll('redirect_uri')
|
|
7
|
+
const {
|
|
8
|
+
scope = 'atproto',
|
|
9
|
+
redirect_uris = [`http://127.0.0.1/`, `http://[::1]/`],
|
|
10
|
+
} = parseOAuthLoopbackClientId(clientId)
|
|
20
11
|
|
|
21
12
|
return {
|
|
22
13
|
client_id: clientId,
|
|
14
|
+
scope,
|
|
15
|
+
redirect_uris,
|
|
23
16
|
client_name: 'Loopback client',
|
|
24
|
-
response_types: ['code
|
|
25
|
-
grant_types: ['authorization_code', '
|
|
26
|
-
scope: 'openid profile offline_access',
|
|
27
|
-
redirect_uris: (redirectUris.length
|
|
28
|
-
? redirectUris
|
|
29
|
-
: (['127.0.0.1', '[::1]'] as const).map(
|
|
30
|
-
(ip) =>
|
|
31
|
-
Object.assign(new URL(pathname, origin), { hostname: ip }).href,
|
|
32
|
-
)) as [string, ...string[]],
|
|
17
|
+
response_types: ['code'],
|
|
18
|
+
grant_types: ['authorization_code', 'refresh_token'],
|
|
33
19
|
token_endpoint_auth_method: 'none',
|
|
34
20
|
application_type: 'native',
|
|
35
21
|
dpop_bound_access_tokens: true,
|
package/src/index.ts
CHANGED
|
@@ -1,25 +1,38 @@
|
|
|
1
1
|
export * from './constants.js'
|
|
2
2
|
export * from './util.js'
|
|
3
3
|
|
|
4
|
-
export * from './access-token.js'
|
|
5
4
|
export * from './atproto-loopback-client-metadata.js'
|
|
6
|
-
export * from './oauth-
|
|
7
|
-
export * from './oauth-
|
|
8
|
-
export * from './oauth-authentication-request-parameters.js'
|
|
5
|
+
export * from './oauth-access-token.js'
|
|
6
|
+
export * from './oauth-authorization-code-grant-token-request.js'
|
|
9
7
|
export * from './oauth-authorization-details.js'
|
|
8
|
+
export * from './oauth-authorization-request-jar.js'
|
|
9
|
+
export * from './oauth-authorization-request-par.js'
|
|
10
|
+
export * from './oauth-authorization-request-parameters.js'
|
|
11
|
+
export * from './oauth-authorization-request-query.js'
|
|
12
|
+
export * from './oauth-authorization-request-uri.js'
|
|
10
13
|
export * from './oauth-authorization-server-metadata.js'
|
|
14
|
+
export * from './oauth-client-credentials-grant-token-request.js'
|
|
11
15
|
export * from './oauth-client-credentials.js'
|
|
16
|
+
export * from './oauth-client-id-discoverable.js'
|
|
17
|
+
export * from './oauth-client-id-loopback.js'
|
|
12
18
|
export * from './oauth-client-id.js'
|
|
13
|
-
export * from './oauth-client-identification.js'
|
|
14
19
|
export * from './oauth-client-metadata.js'
|
|
15
20
|
export * from './oauth-endpoint-auth-method.js'
|
|
16
21
|
export * from './oauth-endpoint-name.js'
|
|
17
22
|
export * from './oauth-grant-type.js'
|
|
23
|
+
export * from './oauth-introspection-response.js'
|
|
18
24
|
export * from './oauth-issuer-identifier.js'
|
|
19
25
|
export * from './oauth-par-response.js'
|
|
26
|
+
export * from './oauth-password-grant-token-request.js'
|
|
20
27
|
export * from './oauth-protected-resource-metadata.js'
|
|
28
|
+
export * from './oauth-refresh-token-grant-token-request.js'
|
|
29
|
+
export * from './oauth-refresh-token.js'
|
|
30
|
+
export * from './oauth-request-uri.js'
|
|
21
31
|
export * from './oauth-response-mode.js'
|
|
22
32
|
export * from './oauth-response-type.js'
|
|
33
|
+
export * from './oauth-scope.js'
|
|
34
|
+
export * from './oauth-token-identification.js'
|
|
35
|
+
export * from './oauth-token-request.js'
|
|
23
36
|
export * from './oauth-token-response.js'
|
|
24
37
|
export * from './oauth-token-type.js'
|
|
25
38
|
export * from './oidc-claims-parameter.js'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
export const oauthAuthorizationCodeGrantTokenRequestSchema = z.object({
|
|
4
|
+
grant_type: z.literal('authorization_code'),
|
|
5
|
+
code: z.string().min(1),
|
|
6
|
+
redirect_uri: z.string().url(),
|
|
7
|
+
/** @see {@link https://datatracker.ietf.org/doc/html/rfc7636#section-4.1} */
|
|
8
|
+
code_verifier: z
|
|
9
|
+
.string()
|
|
10
|
+
.min(43)
|
|
11
|
+
.max(128)
|
|
12
|
+
.regex(/^[a-zA-Z0-9-._~]+$/)
|
|
13
|
+
.optional(),
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export type OAuthAuthorizationCodeGrantTokenRequest = z.infer<
|
|
17
|
+
typeof oauthAuthorizationCodeGrantTokenRequestSchema
|
|
18
|
+
>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { signedJwtSchema, unsignedJwtSchema } from '@atproto/jwk'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
|
|
4
|
+
export const oauthAuthorizationRequestJarSchema = z.object({
|
|
5
|
+
/**
|
|
6
|
+
* AuthorizationRequest inside a JWT:
|
|
7
|
+
* - "iat" is required and **MUST** be less than one minute
|
|
8
|
+
*
|
|
9
|
+
* @see {@link https://datatracker.ietf.org/doc/html/rfc9101}
|
|
10
|
+
*/
|
|
11
|
+
request: z.union([signedJwtSchema, unsignedJwtSchema]),
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
export type OAuthAuthorizationRequestJar = z.infer<
|
|
15
|
+
typeof oauthAuthorizationRequestJarSchema
|
|
16
|
+
>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import { oauthAuthorizationRequestJarSchema } from './oauth-authorization-request-jar.js'
|
|
4
|
+
import { oauthAuthorizationRequestParametersSchema } from './oauth-authorization-request-parameters.js'
|
|
5
|
+
|
|
6
|
+
export const oauthAuthorizationRequestParSchema = z.union([
|
|
7
|
+
oauthAuthorizationRequestParametersSchema,
|
|
8
|
+
oauthAuthorizationRequestJarSchema,
|
|
9
|
+
])
|
|
10
|
+
|
|
11
|
+
export type OAuthAuthorizationRequestPar = z.infer<
|
|
12
|
+
typeof oauthAuthorizationRequestParSchema
|
|
13
|
+
>
|
package/src/{oauth-authentication-request-parameters.ts → oauth-authorization-request-parameters.ts}
RENAMED
|
@@ -3,6 +3,9 @@ import { z } from 'zod'
|
|
|
3
3
|
|
|
4
4
|
import { oauthAuthorizationDetailsSchema } from './oauth-authorization-details.js'
|
|
5
5
|
import { oauthClientIdSchema } from './oauth-client-id.js'
|
|
6
|
+
import { oauthCodeChallengeMethodSchema } from './oauth-code-challenge-method.js'
|
|
7
|
+
import { oauthResponseTypeSchema } from './oauth-response-type.js'
|
|
8
|
+
import { oauthScopeSchema } from './oauth-scope.js'
|
|
6
9
|
import { oidcClaimsParameterSchema } from './oidc-claims-parameter.js'
|
|
7
10
|
import { oidcClaimsPropertiesSchema } from './oidc-claims-properties.js'
|
|
8
11
|
import { oidcEntityTypeSchema } from './oidc-entity-type.js'
|
|
@@ -10,44 +13,32 @@ import { oidcEntityTypeSchema } from './oidc-entity-type.js'
|
|
|
10
13
|
/**
|
|
11
14
|
* @see {@link https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest | OIDC}
|
|
12
15
|
*/
|
|
13
|
-
export const
|
|
16
|
+
export const oauthAuthorizationRequestParametersSchema = z.object({
|
|
14
17
|
client_id: oauthClientIdSchema,
|
|
15
|
-
|
|
16
18
|
state: z.string().optional(),
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
response_type: z.enum([
|
|
21
|
-
// OAuth2 (https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-10#section-4.1.1)
|
|
22
|
-
'code',
|
|
23
|
-
'token',
|
|
24
|
-
|
|
25
|
-
// OIDC (https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html)
|
|
26
|
-
'id_token',
|
|
27
|
-
'none',
|
|
28
|
-
'code token',
|
|
29
|
-
'code id_token',
|
|
30
|
-
'id_token token',
|
|
31
|
-
'code id_token token',
|
|
32
|
-
]),
|
|
33
|
-
|
|
34
|
-
// Default depend on response_type
|
|
35
|
-
response_mode: z.enum(['query', 'fragment', 'form_post']).optional(),
|
|
19
|
+
redirect_uri: z.string().url().optional(),
|
|
20
|
+
scope: oauthScopeSchema.optional(),
|
|
21
|
+
response_type: oauthResponseTypeSchema,
|
|
36
22
|
|
|
37
23
|
// PKCE
|
|
24
|
+
|
|
38
25
|
code_challenge: z.string().optional(),
|
|
39
|
-
code_challenge_method:
|
|
26
|
+
code_challenge_method: oauthCodeChallengeMethodSchema
|
|
27
|
+
.default('S256')
|
|
28
|
+
.optional(),
|
|
40
29
|
|
|
41
|
-
|
|
30
|
+
// DPOP
|
|
42
31
|
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
.string()
|
|
46
|
-
.regex(/^[a-zA-Z0-9_]+( [a-zA-Z0-9_]+)*$/)
|
|
47
|
-
.optional(),
|
|
32
|
+
// https://datatracker.ietf.org/doc/html/rfc9449#section-12.3
|
|
33
|
+
dpop_jkt: z.string().optional(),
|
|
48
34
|
|
|
49
35
|
// OIDC
|
|
50
36
|
|
|
37
|
+
// Default depend on response_type
|
|
38
|
+
response_mode: z.enum(['query', 'fragment', 'form_post']).optional(),
|
|
39
|
+
|
|
40
|
+
nonce: z.string().optional(),
|
|
41
|
+
|
|
51
42
|
// Specifies the allowable elapsed time in seconds since the last time the
|
|
52
43
|
// End-User was actively authenticated by the OP. If the elapsed time is
|
|
53
44
|
// greater than this value, the OP MUST attempt to actively re-authenticate
|
|
@@ -97,8 +88,8 @@ export const oauthAuthenticationRequestParametersSchema = z.object({
|
|
|
97
88
|
})
|
|
98
89
|
|
|
99
90
|
/**
|
|
100
|
-
* @see {
|
|
91
|
+
* @see {oauthAuthorizationRequestParametersSchema}
|
|
101
92
|
*/
|
|
102
|
-
export type
|
|
103
|
-
typeof
|
|
93
|
+
export type OAuthAuthorizationRequestParameters = z.infer<
|
|
94
|
+
typeof oauthAuthorizationRequestParametersSchema
|
|
104
95
|
>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import { oauthAuthorizationRequestJarSchema } from './oauth-authorization-request-jar.js'
|
|
4
|
+
import { oauthAuthorizationRequestParametersSchema } from './oauth-authorization-request-parameters.js'
|
|
5
|
+
import { oauthAuthorizationRequestUriSchema } from './oauth-authorization-request-uri.js'
|
|
6
|
+
|
|
7
|
+
export const oauthAuthorizationRequestQuerySchema = z.union([
|
|
8
|
+
oauthAuthorizationRequestParametersSchema,
|
|
9
|
+
oauthAuthorizationRequestJarSchema,
|
|
10
|
+
oauthAuthorizationRequestUriSchema,
|
|
11
|
+
])
|
|
12
|
+
|
|
13
|
+
export type OAuthAuthorizationRequestQuery = z.infer<
|
|
14
|
+
typeof oauthAuthorizationRequestQuerySchema
|
|
15
|
+
>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import { oauthRequestUriSchema } from './oauth-request-uri.js'
|
|
4
|
+
|
|
5
|
+
export const oauthAuthorizationRequestUriSchema = z.object({
|
|
6
|
+
request_uri: oauthRequestUriSchema,
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
export type OAuthAuthorizationRequestUri = z.infer<
|
|
10
|
+
typeof oauthAuthorizationRequestUriSchema
|
|
11
|
+
>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
|
|
3
|
+
import { oauthCodeChallengeMethodSchema } from './oauth-code-challenge-method.js'
|
|
3
4
|
import { oauthIssuerIdentifierSchema } from './oauth-issuer-identifier.js'
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -19,7 +20,10 @@ export const oauthAuthorizationServerMetadataSchema = z.object({
|
|
|
19
20
|
response_types_supported: z.array(z.string()).optional(),
|
|
20
21
|
response_modes_supported: z.array(z.string()).optional(),
|
|
21
22
|
grant_types_supported: z.array(z.string()).optional(),
|
|
22
|
-
code_challenge_methods_supported: z
|
|
23
|
+
code_challenge_methods_supported: z
|
|
24
|
+
.array(oauthCodeChallengeMethodSchema)
|
|
25
|
+
.min(1)
|
|
26
|
+
.optional(),
|
|
23
27
|
ui_locales_supported: z.array(z.string()).optional(),
|
|
24
28
|
id_token_signing_alg_values_supported: z.array(z.string()).optional(),
|
|
25
29
|
display_values_supported: z.array(z.string()).optional(),
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
export const oauthClientCredentialsGrantTokenRequestSchema = z.object({
|
|
4
|
+
grant_type: z.literal('client_credentials'),
|
|
5
|
+
})
|
|
6
|
+
|
|
7
|
+
export type OAuthClientCredentialsGrantTokenRequest = z.infer<
|
|
8
|
+
typeof oauthClientCredentialsGrantTokenRequestSchema
|
|
9
|
+
>
|
|
@@ -14,19 +14,39 @@ export const oauthClientCredentialsJwtBearerSchema = z.object({
|
|
|
14
14
|
* - The JWT MAY contain a "jti" (JWT ID) claim that provides a unique identifier for the token.
|
|
15
15
|
* - Note that the authorization server may reject JWTs with an "exp" claim value that is unreasonably far in the future.
|
|
16
16
|
*
|
|
17
|
-
* @see {@link https://datatracker.ietf.org/doc/html/
|
|
17
|
+
* @see {@link https://datatracker.ietf.org/doc/html/rfc7523#section-3}
|
|
18
18
|
*/
|
|
19
19
|
client_assertion: signedJwtSchema,
|
|
20
20
|
})
|
|
21
21
|
|
|
22
|
+
export type OAuthClientCredentialsJwtBearer = z.infer<
|
|
23
|
+
typeof oauthClientCredentialsJwtBearerSchema
|
|
24
|
+
>
|
|
25
|
+
|
|
22
26
|
export const oauthClientCredentialsSecretPostSchema = z.object({
|
|
23
27
|
client_id: oauthClientIdSchema,
|
|
24
28
|
client_secret: z.string(),
|
|
25
29
|
})
|
|
26
30
|
|
|
31
|
+
export type OAuthClientCredentialsSecretPost = z.infer<
|
|
32
|
+
typeof oauthClientCredentialsSecretPostSchema
|
|
33
|
+
>
|
|
34
|
+
|
|
35
|
+
export const oauthClientCredentialsNoneSchema = z.object({
|
|
36
|
+
client_id: oauthClientIdSchema,
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
export type OAuthClientCredentialsNone = z.infer<
|
|
40
|
+
typeof oauthClientCredentialsNoneSchema
|
|
41
|
+
>
|
|
42
|
+
|
|
43
|
+
//
|
|
44
|
+
|
|
27
45
|
export const oauthClientCredentialsSchema = z.union([
|
|
28
46
|
oauthClientCredentialsJwtBearerSchema,
|
|
29
47
|
oauthClientCredentialsSecretPostSchema,
|
|
48
|
+
// Must be last since it is less specific
|
|
49
|
+
oauthClientCredentialsNoneSchema,
|
|
30
50
|
])
|
|
31
51
|
|
|
32
52
|
export type OAuthClientCredentials = z.infer<
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import { parseOAuthClientIdUrl } from './oauth-client-id-url.js'
|
|
2
1
|
import { OAuthClientId } from './oauth-client-id.js'
|
|
3
|
-
import {
|
|
2
|
+
import { extractUrlPath, isHostnameIP } from './util.js'
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* @see {@link https://drafts.aaronpk.com/draft-parecki-oauth-client-id-metadata-document/draft-parecki-oauth-client-id-metadata-document.html}
|
|
7
6
|
*/
|
|
8
7
|
export type OAuthClientIdDiscoverable = OAuthClientId & `https://${string}`
|
|
9
8
|
|
|
10
|
-
export function isOAuthClientIdDiscoverable
|
|
11
|
-
clientId:
|
|
12
|
-
): clientId is
|
|
9
|
+
export function isOAuthClientIdDiscoverable(
|
|
10
|
+
clientId: string,
|
|
11
|
+
): clientId is OAuthClientIdDiscoverable {
|
|
13
12
|
try {
|
|
14
13
|
parseOAuthDiscoverableClientId(clientId)
|
|
15
14
|
return true
|
|
@@ -18,48 +17,52 @@ export function isOAuthClientIdDiscoverable<C extends OAuthClientId>(
|
|
|
18
17
|
}
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
export function
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
export function assertOAuthDiscoverableClientId(
|
|
21
|
+
value: string,
|
|
22
|
+
): asserts value is OAuthClientIdDiscoverable {
|
|
23
|
+
void parseOAuthDiscoverableClientId(value)
|
|
24
|
+
}
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
26
|
+
export function parseOAuthDiscoverableClientId(clientId: string): URL {
|
|
27
|
+
const url = new URL(clientId)
|
|
29
28
|
|
|
30
29
|
if (url.protocol !== 'https:') {
|
|
31
30
|
throw new TypeError('ClientID must use the "https:" protocol')
|
|
32
31
|
}
|
|
33
32
|
|
|
33
|
+
if (url.username || url.password) {
|
|
34
|
+
throw new TypeError('ClientID must not contain credentials')
|
|
35
|
+
}
|
|
36
|
+
|
|
34
37
|
if (url.hash) {
|
|
35
38
|
throw new TypeError('ClientID must not contain a fragment')
|
|
36
39
|
}
|
|
37
40
|
|
|
38
|
-
if (url.
|
|
39
|
-
throw new TypeError('ClientID must not
|
|
41
|
+
if (url.hostname === 'localhost') {
|
|
42
|
+
throw new TypeError('ClientID hostname must not be "localhost"')
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
if (url.pathname === '/') {
|
|
43
46
|
throw new TypeError(
|
|
44
|
-
'ClientID must contain a path (e.g. "/client-metadata")',
|
|
47
|
+
'ClientID must contain a path component (e.g. "/client-metadata.json")',
|
|
45
48
|
)
|
|
46
49
|
}
|
|
47
50
|
|
|
48
|
-
if (url.pathname
|
|
49
|
-
throw new TypeError('ClientID must not end with a trailing slash')
|
|
51
|
+
if (url.pathname.endsWith('/')) {
|
|
52
|
+
throw new TypeError('ClientID path must not end with a trailing slash')
|
|
50
53
|
}
|
|
51
54
|
|
|
52
|
-
if (url.
|
|
53
|
-
throw new TypeError(
|
|
54
|
-
`ClientID must not contain any double slashes in its path`,
|
|
55
|
-
)
|
|
55
|
+
if (isHostnameIP(url.hostname)) {
|
|
56
|
+
throw new TypeError('ClientID hostname must not be an IP address')
|
|
56
57
|
}
|
|
57
58
|
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
if (
|
|
62
|
-
throw new TypeError(
|
|
59
|
+
// URL constructor normalizes the URL, so we extract the path manually to
|
|
60
|
+
// avoid normalization, then compare it to the normalized path to ensure
|
|
61
|
+
// that the URL does not contain path traversal or other unexpected characters
|
|
62
|
+
if (extractUrlPath(clientId) !== url.pathname) {
|
|
63
|
+
throw new TypeError(
|
|
64
|
+
`ClientID must be in canonical form ("${url.href}", got "${clientId}")`,
|
|
65
|
+
)
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
return url
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import { parseOAuthClientIdUrl } from './oauth-client-id-url.js'
|
|
2
1
|
import { OAuthClientId } from './oauth-client-id.js'
|
|
2
|
+
import { OAuthScope, oauthScopeSchema } from './oauth-scope.js'
|
|
3
|
+
import { isLoopbackHost, safeUrl } from './util.js'
|
|
4
|
+
|
|
5
|
+
const OAUTH_CLIENT_ID_LOOPBACK_URL = 'http://localhost'
|
|
3
6
|
|
|
4
7
|
export type OAuthClientIdLoopback = OAuthClientId &
|
|
5
|
-
|
|
8
|
+
`${typeof OAUTH_CLIENT_ID_LOOPBACK_URL}${'' | '/'}${'' | `?${string}`}`
|
|
6
9
|
|
|
7
|
-
export function isOAuthClientIdLoopback
|
|
8
|
-
clientId:
|
|
9
|
-
): clientId is
|
|
10
|
+
export function isOAuthClientIdLoopback(
|
|
11
|
+
clientId: string,
|
|
12
|
+
): clientId is OAuthClientIdLoopback {
|
|
10
13
|
try {
|
|
11
14
|
parseOAuthLoopbackClientId(clientId)
|
|
12
15
|
return true
|
|
@@ -15,44 +18,89 @@ export function isOAuthClientIdLoopback<C extends OAuthClientId>(
|
|
|
15
18
|
}
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
export function
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
export function assertOAuthLoopbackClientId(
|
|
22
|
+
clientId: string,
|
|
23
|
+
): asserts clientId is OAuthClientIdLoopback {
|
|
24
|
+
void parseOAuthLoopbackClientId(clientId)
|
|
25
|
+
}
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
// @TODO: should we turn this into a zod schema? (more coherent error with other
|
|
28
|
+
// validation functions)
|
|
29
|
+
export function parseOAuthLoopbackClientId(clientId: string): {
|
|
30
|
+
scope?: OAuthScope
|
|
31
|
+
redirect_uris?: [string, ...string[]]
|
|
32
|
+
} {
|
|
33
|
+
if (!clientId.startsWith(OAUTH_CLIENT_ID_LOOPBACK_URL)) {
|
|
34
|
+
throw new TypeError(
|
|
35
|
+
`Loopback ClientID must start with "${OAUTH_CLIENT_ID_LOOPBACK_URL}"`,
|
|
36
|
+
)
|
|
37
|
+
} else if (clientId.includes('#', OAUTH_CLIENT_ID_LOOPBACK_URL.length)) {
|
|
38
|
+
throw new TypeError('Loopback ClientID must not contain a hash component')
|
|
25
39
|
}
|
|
26
40
|
|
|
27
|
-
|
|
28
|
-
|
|
41
|
+
const queryStringIdx =
|
|
42
|
+
clientId.length > OAUTH_CLIENT_ID_LOOPBACK_URL.length &&
|
|
43
|
+
clientId[OAUTH_CLIENT_ID_LOOPBACK_URL.length] === '/'
|
|
44
|
+
? OAUTH_CLIENT_ID_LOOPBACK_URL.length + 1
|
|
45
|
+
: OAUTH_CLIENT_ID_LOOPBACK_URL.length
|
|
46
|
+
|
|
47
|
+
if (clientId.length === queryStringIdx) {
|
|
48
|
+
return {} // no query string to parse
|
|
29
49
|
}
|
|
30
50
|
|
|
31
|
-
if (
|
|
32
|
-
throw new TypeError('Loopback ClientID must not contain a
|
|
51
|
+
if (clientId[queryStringIdx] !== '?') {
|
|
52
|
+
throw new TypeError('Loopback ClientID must not contain a path component')
|
|
33
53
|
}
|
|
34
54
|
|
|
35
|
-
|
|
36
|
-
|
|
55
|
+
const searchParams = new URLSearchParams(clientId.slice(queryStringIdx + 1))
|
|
56
|
+
|
|
57
|
+
for (const name of searchParams.keys()) {
|
|
58
|
+
if (name !== 'redirect_uri' && name !== 'scope') {
|
|
59
|
+
throw new TypeError(`Invalid query parameter "${name}" in client ID`)
|
|
60
|
+
}
|
|
37
61
|
}
|
|
38
62
|
|
|
39
|
-
|
|
40
|
-
|
|
63
|
+
const scope = searchParams.get('scope') ?? undefined
|
|
64
|
+
if (scope != null) {
|
|
65
|
+
if (searchParams.getAll('scope').length > 1) {
|
|
66
|
+
throw new TypeError(
|
|
67
|
+
'Loopback ClientID must contain at most one scope query parameter',
|
|
68
|
+
)
|
|
69
|
+
} else if (!oauthScopeSchema.safeParse(scope).success) {
|
|
70
|
+
throw new TypeError('Invalid scope query parameter in client ID')
|
|
71
|
+
}
|
|
41
72
|
}
|
|
42
73
|
|
|
43
|
-
|
|
74
|
+
const redirect_uris = searchParams.has('redirect_uri')
|
|
75
|
+
? (searchParams.getAll('redirect_uri') as [string, ...string[]])
|
|
76
|
+
: undefined
|
|
44
77
|
|
|
45
|
-
if (
|
|
46
|
-
|
|
78
|
+
if (redirect_uris) {
|
|
79
|
+
for (const uri of redirect_uris) {
|
|
80
|
+
const url = safeUrl(uri)
|
|
81
|
+
if (!url) {
|
|
82
|
+
throw new TypeError(`Invalid redirect_uri in client ID: ${uri}`)
|
|
83
|
+
}
|
|
84
|
+
if (url.protocol !== 'http:') {
|
|
85
|
+
throw new TypeError(
|
|
86
|
+
`Loopback ClientID must use "http:" redirect_uri's (got ${uri})`,
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
if (url.hostname === 'localhost') {
|
|
90
|
+
throw new TypeError(
|
|
91
|
+
`Loopback ClientID must not use "localhost" as redirect_uri hostname (got ${uri})`,
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
if (!isLoopbackHost(url.hostname)) {
|
|
95
|
+
throw new TypeError(
|
|
96
|
+
`Loopback ClientID must use loopback addresses as redirect_uri's (got ${uri})`,
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
47
100
|
}
|
|
48
101
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
)
|
|
102
|
+
return {
|
|
103
|
+
scope,
|
|
104
|
+
redirect_uris,
|
|
53
105
|
}
|
|
54
|
-
|
|
55
|
-
// Note: Query string is allowed
|
|
56
|
-
|
|
57
|
-
return url
|
|
58
106
|
}
|
|
@@ -5,6 +5,7 @@ import { oauthClientIdSchema } from './oauth-client-id.js'
|
|
|
5
5
|
import { oauthEndpointAuthMethod } from './oauth-endpoint-auth-method.js'
|
|
6
6
|
import { oauthGrantTypeSchema } from './oauth-grant-type.js'
|
|
7
7
|
import { oauthResponseTypeSchema } from './oauth-response-type.js'
|
|
8
|
+
import { oauthScopeSchema } from './oauth-scope.js'
|
|
8
9
|
|
|
9
10
|
// https://openid.net/specs/openid-connect-registration-1_0.html
|
|
10
11
|
// https://datatracker.ietf.org/doc/html/rfc7591
|
|
@@ -22,7 +23,7 @@ export const oauthClientMetadataSchema = z.object({
|
|
|
22
23
|
// > If omitted, the default behavior is that the client will use only the
|
|
23
24
|
// > "authorization_code" Grant Type.
|
|
24
25
|
.default(['authorization_code']),
|
|
25
|
-
scope:
|
|
26
|
+
scope: oauthScopeSchema.optional(),
|
|
26
27
|
token_endpoint_auth_method: oauthEndpointAuthMethod
|
|
27
28
|
.default('none')
|
|
28
29
|
.optional(),
|