@atproto/oauth-types 0.1.0
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 +12 -0
- package/LICENSE.txt +7 -0
- package/README.md +3 -0
- package/dist/access-token.d.ts +4 -0
- package/dist/access-token.d.ts.map +1 -0
- package/dist/access-token.js +6 -0
- package/dist/access-token.js.map +1 -0
- package/dist/atproto-loopback-client-metadata.d.ts +3 -0
- package/dist/atproto-loopback-client-metadata.d.ts.map +1 -0
- package/dist/atproto-loopback-client-metadata.js +26 -0
- package/dist/atproto-loopback-client-metadata.js.map +1 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +11 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/oauth-authentication-request-parameters.d.ts +128 -0
- package/dist/oauth-authentication-request-parameters.d.ts.map +1 -0
- package/dist/oauth-authentication-request-parameters.js +76 -0
- package/dist/oauth-authentication-request-parameters.js.map +1 -0
- package/dist/oauth-authorization-details.d.ts +54 -0
- package/dist/oauth-authorization-details.d.ts.map +1 -0
- package/dist/oauth-authorization-details.js +20 -0
- package/dist/oauth-authorization-details.js.map +1 -0
- package/dist/oauth-authorization-server-metadata.d.ts +428 -0
- package/dist/oauth-authorization-server-metadata.d.ts.map +1 -0
- package/dist/oauth-authorization-server-metadata.js +88 -0
- package/dist/oauth-authorization-server-metadata.js.map +1 -0
- package/dist/oauth-client-credentials.d.ts +66 -0
- package/dist/oauth-client-credentials.d.ts.map +1 -0
- package/dist/oauth-client-credentials.js +30 -0
- package/dist/oauth-client-credentials.js.map +1 -0
- package/dist/oauth-client-id-discoverable.d.ts +8 -0
- package/dist/oauth-client-id-discoverable.d.ts.map +1 -0
- package/dist/oauth-client-id-discoverable.js +48 -0
- package/dist/oauth-client-id-discoverable.js.map +1 -0
- package/dist/oauth-client-id-loopback.d.ts +5 -0
- package/dist/oauth-client-id-loopback.d.ts.map +1 -0
- package/dist/oauth-client-id-loopback.js +44 -0
- package/dist/oauth-client-id-loopback.js.map +1 -0
- package/dist/oauth-client-id-url.d.ts +3 -0
- package/dist/oauth-client-id-url.d.ts.map +1 -0
- package/dist/oauth-client-id-url.js +21 -0
- package/dist/oauth-client-id-url.js.map +1 -0
- package/dist/oauth-client-id.d.ts +4 -0
- package/dist/oauth-client-id.d.ts.map +1 -0
- package/dist/oauth-client-id.js +6 -0
- package/dist/oauth-client-id.js.map +1 -0
- package/dist/oauth-client-identification.d.ts +31 -0
- package/dist/oauth-client-identification.d.ts.map +1 -0
- package/dist/oauth-client-identification.js +12 -0
- package/dist/oauth-client-identification.js.map +1 -0
- package/dist/oauth-client-metadata.d.ts +1576 -0
- package/dist/oauth-client-metadata.d.ts.map +1 -0
- package/dist/oauth-client-metadata.js +70 -0
- package/dist/oauth-client-metadata.js.map +1 -0
- package/dist/oauth-endpoint-auth-method.d.ts +4 -0
- package/dist/oauth-endpoint-auth-method.d.ts.map +1 -0
- package/dist/oauth-endpoint-auth-method.js +14 -0
- package/dist/oauth-endpoint-auth-method.js.map +1 -0
- package/dist/oauth-endpoint-name.d.ts +2 -0
- package/dist/oauth-endpoint-name.d.ts.map +1 -0
- package/dist/oauth-endpoint-name.js +3 -0
- package/dist/oauth-endpoint-name.js.map +1 -0
- package/dist/oauth-grant-type.d.ts +4 -0
- package/dist/oauth-grant-type.d.ts.map +1 -0
- package/dist/oauth-grant-type.js +14 -0
- package/dist/oauth-grant-type.js.map +1 -0
- package/dist/oauth-issuer-identifier.d.ts +3 -0
- package/dist/oauth-issuer-identifier.d.ts.map +1 -0
- package/dist/oauth-issuer-identifier.js +59 -0
- package/dist/oauth-issuer-identifier.js.map +1 -0
- package/dist/oauth-par-response.d.ts +10 -0
- package/dist/oauth-par-response.d.ts.map +1 -0
- package/dist/oauth-par-response.js +8 -0
- package/dist/oauth-par-response.js.map +1 -0
- package/dist/oauth-protected-resource-metadata.d.ts +90 -0
- package/dist/oauth-protected-resource-metadata.d.ts.map +1 -0
- package/dist/oauth-protected-resource-metadata.js +75 -0
- package/dist/oauth-protected-resource-metadata.js.map +1 -0
- package/dist/oauth-response-mode.d.ts +4 -0
- package/dist/oauth-response-mode.d.ts.map +1 -0
- package/dist/oauth-response-mode.js +10 -0
- package/dist/oauth-response-mode.js.map +1 -0
- package/dist/oauth-response-type.d.ts +4 -0
- package/dist/oauth-response-type.d.ts.map +1 -0
- package/dist/oauth-response-type.js +17 -0
- package/dist/oauth-response-type.js.map +1 -0
- package/dist/oauth-token-response.d.ts +103 -0
- package/dist/oauth-token-response.d.ts.map +1 -0
- package/dist/oauth-token-response.js +26 -0
- package/dist/oauth-token-response.js.map +1 -0
- package/dist/oauth-token-type.d.ts +4 -0
- package/dist/oauth-token-type.d.ts.map +1 -0
- package/dist/oauth-token-type.js +16 -0
- package/dist/oauth-token-type.js.map +1 -0
- package/dist/oidc-claims-parameter.d.ts +4 -0
- package/dist/oidc-claims-parameter.d.ts.map +1 -0
- package/dist/oidc-claims-parameter.js +36 -0
- package/dist/oidc-claims-parameter.js.map +1 -0
- package/dist/oidc-claims-properties.d.ts +16 -0
- package/dist/oidc-claims-properties.d.ts.map +1 -0
- package/dist/oidc-claims-properties.js +11 -0
- package/dist/oidc-claims-properties.js.map +1 -0
- package/dist/oidc-entity-type.d.ts +4 -0
- package/dist/oidc-entity-type.d.ts.map +1 -0
- package/dist/oidc-entity-type.js +6 -0
- package/dist/oidc-entity-type.js.map +1 -0
- package/dist/util.d.ts +5 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +23 -0
- package/dist/util.js.map +1 -0
- package/package.json +37 -0
- package/src/access-token.ts +4 -0
- package/src/atproto-loopback-client-metadata.ts +30 -0
- package/src/constants.ts +9 -0
- package/src/index.ts +27 -0
- package/src/oauth-authentication-request-parameters.ts +104 -0
- package/src/oauth-authorization-details.ts +28 -0
- package/src/oauth-authorization-server-metadata.ts +106 -0
- package/src/oauth-client-credentials.ts +34 -0
- package/src/oauth-client-id-discoverable.ts +66 -0
- package/src/oauth-client-id-loopback.ts +58 -0
- package/src/oauth-client-id-url.ts +25 -0
- package/src/oauth-client-id.ts +4 -0
- package/src/oauth-client-identification.ts +14 -0
- package/src/oauth-client-metadata.ts +75 -0
- package/src/oauth-endpoint-auth-method.ts +13 -0
- package/src/oauth-endpoint-name.ts +5 -0
- package/src/oauth-grant-type.ts +13 -0
- package/src/oauth-issuer-identifier.ts +61 -0
- package/src/oauth-par-response.ts +7 -0
- package/src/oauth-protected-resource-metadata.ts +85 -0
- package/src/oauth-response-mode.ts +9 -0
- package/src/oauth-response-type.ts +17 -0
- package/src/oauth-token-response.ts +29 -0
- package/src/oauth-token-type.ts +15 -0
- package/src/oidc-claims-parameter.ts +40 -0
- package/src/oidc-claims-properties.ts +11 -0
- package/src/oidc-entity-type.ts +5 -0
- package/src/util.ts +20 -0
- package/tsconfig.build.json +8 -0
- package/tsconfig.json +4 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-token-response.js","sourceRoot":"","sources":["../src/oauth-token-response.ts"],"names":[],"mappings":";;;AAAA,sCAA8C;AAC9C,6BAAuB;AAEvB,qFAAkF;AAClF,+DAA4D;AAE5D;;GAEG;AACU,QAAA,wBAAwB,GAAG,OAAC;KACtC,MAAM,CAAC;IACN,YAAY,EAAE,OAAC,CAAC,MAAM,EAAE;IACxB,UAAU,EAAE,0CAAoB;IAChC,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACnC,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,QAAQ,EAAE,qBAAe,CAAC,QAAQ,EAAE;IACpC,aAAa,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACpC,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjC,qBAAqB,EAAE,gEAA+B,CAAC,QAAQ,EAAE;CAClE,CAAC;IACF,0DAA0D;IAC1D,qEAAqE;KACpE,WAAW,EAAE,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const oauthTokenTypeSchema: z.ZodUnion<[z.ZodEffects<z.ZodString, "DPoP", string>, z.ZodEffects<z.ZodString, "Bearer", string>]>;
|
|
3
|
+
export type OAuthTokenType = z.infer<typeof oauthTokenTypeSchema>;
|
|
4
|
+
//# sourceMappingURL=oauth-token-type.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-token-type.d.ts","sourceRoot":"","sources":["../src/oauth-token-type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,oBAAoB,sGAS/B,CAAA;AAEF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.oauthTokenTypeSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
// Case insensitive input, normalized output
|
|
6
|
+
exports.oauthTokenTypeSchema = zod_1.z.union([
|
|
7
|
+
zod_1.z
|
|
8
|
+
.string()
|
|
9
|
+
.regex(/^DPoP$/i)
|
|
10
|
+
.transform(() => 'DPoP'),
|
|
11
|
+
zod_1.z
|
|
12
|
+
.string()
|
|
13
|
+
.regex(/^Bearer$/i)
|
|
14
|
+
.transform(() => 'Bearer'),
|
|
15
|
+
]);
|
|
16
|
+
//# sourceMappingURL=oauth-token-type.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-token-type.js","sourceRoot":"","sources":["../src/oauth-token-type.ts"],"names":[],"mappings":";;;AAAA,6BAAuB;AAEvB,4CAA4C;AAC/B,QAAA,oBAAoB,GAAG,OAAC,CAAC,KAAK,CAAC;IAC1C,OAAC;SACE,MAAM,EAAE;SACR,KAAK,CAAC,SAAS,CAAC;SAChB,SAAS,CAAC,GAAG,EAAE,CAAC,MAAe,CAAC;IACnC,OAAC;SACE,MAAM,EAAE;SACR,KAAK,CAAC,WAAW,CAAC;SAClB,SAAS,CAAC,GAAG,EAAE,CAAC,QAAiB,CAAC;CACtC,CAAC,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const oidcClaimsParameterSchema: z.ZodEnum<["auth_time", "nonce", "acr", "name", "family_name", "given_name", "middle_name", "nickname", "preferred_username", "gender", "picture", "profile", "website", "birthdate", "zoneinfo", "locale", "updated_at", "email", "email_verified", "phone_number", "phone_number_verified", "address"]>;
|
|
3
|
+
export type OidcClaimsParameter = z.infer<typeof oidcClaimsParameterSchema>;
|
|
4
|
+
//# sourceMappingURL=oidc-claims-parameter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc-claims-parameter.d.ts","sourceRoot":"","sources":["../src/oidc-claims-parameter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,yBAAyB,2SAmCpC,CAAA;AAEF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.oidcClaimsParameterSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
exports.oidcClaimsParameterSchema = zod_1.z.enum([
|
|
6
|
+
// https://openid.net/specs/openid-provider-authentication-policy-extension-1_0.html#rfc.section.5.2
|
|
7
|
+
// if client metadata "require_auth_time" is true, this *must* be provided
|
|
8
|
+
'auth_time',
|
|
9
|
+
// OIDC
|
|
10
|
+
'nonce',
|
|
11
|
+
'acr',
|
|
12
|
+
// OpenID: "profile" scope
|
|
13
|
+
'name',
|
|
14
|
+
'family_name',
|
|
15
|
+
'given_name',
|
|
16
|
+
'middle_name',
|
|
17
|
+
'nickname',
|
|
18
|
+
'preferred_username',
|
|
19
|
+
'gender',
|
|
20
|
+
'picture',
|
|
21
|
+
'profile',
|
|
22
|
+
'website',
|
|
23
|
+
'birthdate',
|
|
24
|
+
'zoneinfo',
|
|
25
|
+
'locale',
|
|
26
|
+
'updated_at',
|
|
27
|
+
// OpenID: "email" scope
|
|
28
|
+
'email',
|
|
29
|
+
'email_verified',
|
|
30
|
+
// OpenID: "phone" scope
|
|
31
|
+
'phone_number',
|
|
32
|
+
'phone_number_verified',
|
|
33
|
+
// OpenID: "address" scope
|
|
34
|
+
'address',
|
|
35
|
+
]);
|
|
36
|
+
//# sourceMappingURL=oidc-claims-parameter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc-claims-parameter.js","sourceRoot":"","sources":["../src/oidc-claims-parameter.ts"],"names":[],"mappings":";;;AAAA,6BAAuB;AAEV,QAAA,yBAAyB,GAAG,OAAC,CAAC,IAAI,CAAC;IAC9C,oGAAoG;IACpG,0EAA0E;IAC1E,WAAW;IAEX,OAAO;IACP,OAAO;IACP,KAAK;IAEL,0BAA0B;IAC1B,MAAM;IACN,aAAa;IACb,YAAY;IACZ,aAAa;IACb,UAAU;IACV,oBAAoB;IACpB,QAAQ;IACR,SAAS;IACT,SAAS;IACT,SAAS;IACT,WAAW;IACX,UAAU;IACV,QAAQ;IACR,YAAY;IAEZ,wBAAwB;IACxB,OAAO;IACP,gBAAgB;IAEhB,wBAAwB;IACxB,cAAc;IACd,uBAAuB;IAEvB,0BAA0B;IAC1B,SAAS;CACV,CAAC,CAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const oidcClaimsPropertiesSchema: z.ZodObject<{
|
|
3
|
+
essential: z.ZodOptional<z.ZodBoolean>;
|
|
4
|
+
value: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
5
|
+
values: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>, "many">>;
|
|
6
|
+
}, "strip", z.ZodTypeAny, {
|
|
7
|
+
values?: (string | number | boolean)[] | undefined;
|
|
8
|
+
value?: string | number | boolean | undefined;
|
|
9
|
+
essential?: boolean | undefined;
|
|
10
|
+
}, {
|
|
11
|
+
values?: (string | number | boolean)[] | undefined;
|
|
12
|
+
value?: string | number | boolean | undefined;
|
|
13
|
+
essential?: boolean | undefined;
|
|
14
|
+
}>;
|
|
15
|
+
export type OidcClaimsProperties = z.infer<typeof oidcClaimsPropertiesSchema>;
|
|
16
|
+
//# sourceMappingURL=oidc-claims-properties.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc-claims-properties.d.ts","sourceRoot":"","sources":["../src/oidc-claims-properties.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,0BAA0B;;;;;;;;;;;;EAIrC,CAAA;AAEF,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.oidcClaimsPropertiesSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const oidcClaimsValueSchema = zod_1.z.union([zod_1.z.string(), zod_1.z.number(), zod_1.z.boolean()]);
|
|
6
|
+
exports.oidcClaimsPropertiesSchema = zod_1.z.object({
|
|
7
|
+
essential: zod_1.z.boolean().optional(),
|
|
8
|
+
value: oidcClaimsValueSchema.optional(),
|
|
9
|
+
values: zod_1.z.array(oidcClaimsValueSchema).optional(),
|
|
10
|
+
});
|
|
11
|
+
//# sourceMappingURL=oidc-claims-properties.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc-claims-properties.js","sourceRoot":"","sources":["../src/oidc-claims-properties.ts"],"names":[],"mappings":";;;AAAA,6BAAuB;AAEvB,MAAM,qBAAqB,GAAG,OAAC,CAAC,KAAK,CAAC,CAAC,OAAC,CAAC,MAAM,EAAE,EAAE,OAAC,CAAC,MAAM,EAAE,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;AAE/D,QAAA,0BAA0B,GAAG,OAAC,CAAC,MAAM,CAAC;IACjD,SAAS,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IACjC,KAAK,EAAE,qBAAqB,CAAC,QAAQ,EAAE;IACvC,MAAM,EAAE,OAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,QAAQ,EAAE;CAClD,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc-entity-type.d.ts","sourceRoot":"","sources":["../src/oidc-entity-type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,oBAAoB,qCAAmC,CAAA;AAEpE,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.oidcEntityTypeSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
exports.oidcEntityTypeSchema = zod_1.z.enum(['userinfo', 'id_token']);
|
|
6
|
+
//# sourceMappingURL=oidc-entity-type.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc-entity-type.js","sourceRoot":"","sources":["../src/oidc-entity-type.ts"],"names":[],"mappings":";;;AAAA,6BAAuB;AAEV,QAAA,oBAAoB,GAAG,OAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAA"}
|
package/dist/util.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function isIP(hostname: string): boolean;
|
|
2
|
+
export type LoopbackHost = 'localhost' | '127.0.0.1' | '[::1]';
|
|
3
|
+
export declare function isLoopbackHost(host: unknown): host is LoopbackHost;
|
|
4
|
+
export declare function isLoopbackUrl(input: URL | string): boolean;
|
|
5
|
+
//# sourceMappingURL=util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,wBAAgB,IAAI,CAAC,QAAQ,EAAE,MAAM,WAQpC;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"}
|
package/dist/util.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isLoopbackUrl = exports.isLoopbackHost = exports.isIP = void 0;
|
|
4
|
+
function isIP(hostname) {
|
|
5
|
+
// IPv4
|
|
6
|
+
if (hostname.match(/^\d+\.\d+\.\d+\.\d+$/))
|
|
7
|
+
return true;
|
|
8
|
+
// IPv6
|
|
9
|
+
if (hostname.startsWith('[') && hostname.endsWith(']'))
|
|
10
|
+
return true;
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
exports.isIP = isIP;
|
|
14
|
+
function isLoopbackHost(host) {
|
|
15
|
+
return host === 'localhost' || host === '127.0.0.1' || host === '[::1]';
|
|
16
|
+
}
|
|
17
|
+
exports.isLoopbackHost = isLoopbackHost;
|
|
18
|
+
function isLoopbackUrl(input) {
|
|
19
|
+
const url = typeof input === 'string' ? new URL(input) : input;
|
|
20
|
+
return isLoopbackHost(url.hostname);
|
|
21
|
+
}
|
|
22
|
+
exports.isLoopbackUrl = isLoopbackUrl;
|
|
23
|
+
//# sourceMappingURL=util.js.map
|
package/dist/util.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;;AAAA,SAAgB,IAAI,CAAC,QAAgB;IACnC,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,oBAQC;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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@atproto/oauth-types",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "OAuth typing & validation library",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"atproto",
|
|
8
|
+
"oauth",
|
|
9
|
+
"types",
|
|
10
|
+
"isomorphic"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://atproto.com",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/bluesky-social/atproto",
|
|
16
|
+
"directory": "packages/oauth/oauth-types"
|
|
17
|
+
},
|
|
18
|
+
"type": "commonjs",
|
|
19
|
+
"main": "dist/index.js",
|
|
20
|
+
"types": "dist/index.d.ts",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"default": "./dist/index.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"zod": "^3.23.8",
|
|
29
|
+
"@atproto/jwk": "0.1.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"typescript": "^5.3.3"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc --build tsconfig.build.json"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { isOAuthClientIdLoopback } from './oauth-client-id-loopback.js'
|
|
2
|
+
import { OAuthClientMetadataInput } from './oauth-client-metadata.js'
|
|
3
|
+
import { parseOAuthClientIdUrl } from './oauth-client-id-url.js'
|
|
4
|
+
|
|
5
|
+
export function atprotoLoopbackClientMetadata(
|
|
6
|
+
clientId: string,
|
|
7
|
+
): OAuthClientMetadataInput {
|
|
8
|
+
if (!isOAuthClientIdLoopback(clientId)) {
|
|
9
|
+
throw new TypeError(`Invalid loopback client ID ${clientId}`)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const { origin, pathname, searchParams } = parseOAuthClientIdUrl(clientId)
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
client_id: clientId,
|
|
16
|
+
client_name: 'Loopback client',
|
|
17
|
+
response_types: ['code id_token', 'code'],
|
|
18
|
+
grant_types: ['authorization_code', 'implicit', 'refresh_token'],
|
|
19
|
+
scope: 'openid profile offline_access',
|
|
20
|
+
redirect_uris: searchParams.has('redirect_uri')
|
|
21
|
+
? (searchParams.getAll('redirect_uri') as [string, ...string[]])
|
|
22
|
+
: (['127.0.0.1', '[::1]'].map(
|
|
23
|
+
(ip) =>
|
|
24
|
+
Object.assign(new URL(pathname, origin), { hostname: ip }).href,
|
|
25
|
+
) as [string, ...string[]]),
|
|
26
|
+
token_endpoint_auth_method: 'none',
|
|
27
|
+
application_type: 'native',
|
|
28
|
+
dpop_bound_access_tokens: true,
|
|
29
|
+
}
|
|
30
|
+
}
|
package/src/constants.ts
ADDED
package/src/index.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export * from './constants.js'
|
|
2
|
+
export * from './util.js'
|
|
3
|
+
|
|
4
|
+
export * from './access-token.js'
|
|
5
|
+
export * from './atproto-loopback-client-metadata.js'
|
|
6
|
+
export * from './oauth-client-id-discoverable.js'
|
|
7
|
+
export * from './oauth-client-id-loopback.js'
|
|
8
|
+
export * from './oauth-authentication-request-parameters.js'
|
|
9
|
+
export * from './oauth-authorization-details.js'
|
|
10
|
+
export * from './oauth-authorization-server-metadata.js'
|
|
11
|
+
export * from './oauth-client-credentials.js'
|
|
12
|
+
export * from './oauth-client-id.js'
|
|
13
|
+
export * from './oauth-client-identification.js'
|
|
14
|
+
export * from './oauth-client-metadata.js'
|
|
15
|
+
export * from './oauth-endpoint-auth-method.js'
|
|
16
|
+
export * from './oauth-endpoint-name.js'
|
|
17
|
+
export * from './oauth-grant-type.js'
|
|
18
|
+
export * from './oauth-issuer-identifier.js'
|
|
19
|
+
export * from './oauth-par-response.js'
|
|
20
|
+
export * from './oauth-protected-resource-metadata.js'
|
|
21
|
+
export * from './oauth-response-mode.js'
|
|
22
|
+
export * from './oauth-response-type.js'
|
|
23
|
+
export * from './oauth-token-response.js'
|
|
24
|
+
export * from './oauth-token-type.js'
|
|
25
|
+
export * from './oidc-claims-parameter.js'
|
|
26
|
+
export * from './oidc-claims-properties.js'
|
|
27
|
+
export * from './oidc-entity-type.js'
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { signedJwtSchema } from '@atproto/jwk'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
|
|
4
|
+
import { oauthAuthorizationDetailsSchema } from './oauth-authorization-details.js'
|
|
5
|
+
import { oauthClientIdSchema } from './oauth-client-id.js'
|
|
6
|
+
import { oidcClaimsParameterSchema } from './oidc-claims-parameter.js'
|
|
7
|
+
import { oidcClaimsPropertiesSchema } from './oidc-claims-properties.js'
|
|
8
|
+
import { oidcEntityTypeSchema } from './oidc-entity-type.js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @see {@link https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest | OIDC}
|
|
12
|
+
*/
|
|
13
|
+
export const oauthAuthenticationRequestParametersSchema = z.object({
|
|
14
|
+
client_id: oauthClientIdSchema,
|
|
15
|
+
|
|
16
|
+
state: z.string().optional(),
|
|
17
|
+
nonce: z.string().optional(),
|
|
18
|
+
dpop_jkt: z.string().optional(),
|
|
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(),
|
|
36
|
+
|
|
37
|
+
// PKCE
|
|
38
|
+
code_challenge: z.string().optional(),
|
|
39
|
+
code_challenge_method: z.enum(['S256', 'plain']).default('S256').optional(),
|
|
40
|
+
|
|
41
|
+
redirect_uri: z.string().url().optional(),
|
|
42
|
+
|
|
43
|
+
// email profile openid (other?)
|
|
44
|
+
scope: z
|
|
45
|
+
.string()
|
|
46
|
+
.regex(/^[a-zA-Z0-9_]+( [a-zA-Z0-9_]+)*$/)
|
|
47
|
+
.optional(),
|
|
48
|
+
|
|
49
|
+
// OIDC
|
|
50
|
+
|
|
51
|
+
// Specifies the allowable elapsed time in seconds since the last time the
|
|
52
|
+
// End-User was actively authenticated by the OP. If the elapsed time is
|
|
53
|
+
// greater than this value, the OP MUST attempt to actively re-authenticate
|
|
54
|
+
// the End-User. (The max_age request parameter corresponds to the OpenID 2.0
|
|
55
|
+
// PAPE [OpenID.PAPE] max_auth_age request parameter.) When max_age is used,
|
|
56
|
+
// the ID Token returned MUST include an auth_time Claim Value. Note that
|
|
57
|
+
// max_age=0 is equivalent to prompt=login.
|
|
58
|
+
max_age: z.number().int().min(0).optional(),
|
|
59
|
+
|
|
60
|
+
claims: z
|
|
61
|
+
.record(
|
|
62
|
+
oidcEntityTypeSchema,
|
|
63
|
+
z.record(
|
|
64
|
+
oidcClaimsParameterSchema,
|
|
65
|
+
z.union([z.literal(null), oidcClaimsPropertiesSchema]),
|
|
66
|
+
),
|
|
67
|
+
)
|
|
68
|
+
.optional(),
|
|
69
|
+
|
|
70
|
+
// https://openid.net/specs/openid-connect-core-1_0.html#RegistrationParameter
|
|
71
|
+
// Not supported by this library (yet?)
|
|
72
|
+
// registration: clientMetadataSchema.optional(),
|
|
73
|
+
|
|
74
|
+
login_hint: z.string().min(1).optional(),
|
|
75
|
+
|
|
76
|
+
ui_locales: z
|
|
77
|
+
.string()
|
|
78
|
+
.regex(/^[a-z]{2}(-[A-Z]{2})?( [a-z]{2}(-[A-Z]{2})?)*$/) // fr-CA fr en
|
|
79
|
+
.optional(),
|
|
80
|
+
|
|
81
|
+
// Previous ID Token, should be provided when prompt=none is used
|
|
82
|
+
id_token_hint: signedJwtSchema.optional(),
|
|
83
|
+
|
|
84
|
+
// Type of UI the AS is displayed on
|
|
85
|
+
display: z.enum(['page', 'popup', 'touch']).optional(),
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* - "none" will only be allowed if the user already allowed the client on the same device
|
|
89
|
+
* - "login" will force the user to login again, unless he very recently logged in
|
|
90
|
+
* - "consent" will force the user to consent again
|
|
91
|
+
* - "select_account" will force the user to select an account
|
|
92
|
+
*/
|
|
93
|
+
prompt: z.enum(['none', 'login', 'consent', 'select_account']).optional(),
|
|
94
|
+
|
|
95
|
+
// https://datatracker.ietf.org/doc/html/rfc9396
|
|
96
|
+
authorization_details: oauthAuthorizationDetailsSchema.optional(),
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @see {oauthAuthenticationRequestParametersSchema}
|
|
101
|
+
*/
|
|
102
|
+
export type OAuthAuthenticationRequestParameters = z.infer<
|
|
103
|
+
typeof oauthAuthenticationRequestParametersSchema
|
|
104
|
+
>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @see {@link https://datatracker.ietf.org/doc/html/rfc9396#section-2 | RFC 9396, Section 2}
|
|
5
|
+
*/
|
|
6
|
+
export const oauthAuthorizationDetailSchema = z.object({
|
|
7
|
+
type: z.string(),
|
|
8
|
+
locations: z.array(z.string().url()).optional(),
|
|
9
|
+
actions: z.array(z.string()).optional(),
|
|
10
|
+
datatypes: z.array(z.string()).optional(),
|
|
11
|
+
identifier: z.string().optional(),
|
|
12
|
+
privileges: z.array(z.string()).optional(),
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
export type OAuthAuthorizationDetail = z.infer<
|
|
16
|
+
typeof oauthAuthorizationDetailSchema
|
|
17
|
+
>
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @see {@link https://datatracker.ietf.org/doc/html/rfc9396#section-2 | RFC 9396, Section 2}
|
|
21
|
+
*/
|
|
22
|
+
export const oauthAuthorizationDetailsSchema = z.array(
|
|
23
|
+
oauthAuthorizationDetailSchema,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
export type OAuthAuthorizationDetails = z.infer<
|
|
27
|
+
typeof oauthAuthorizationDetailsSchema
|
|
28
|
+
>
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import { oauthIssuerIdentifierSchema } from './oauth-issuer-identifier.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @see {@link https://datatracker.ietf.org/doc/html/rfc8414}
|
|
7
|
+
*/
|
|
8
|
+
export const oauthAuthorizationServerMetadataSchema = z.object({
|
|
9
|
+
issuer: oauthIssuerIdentifierSchema,
|
|
10
|
+
|
|
11
|
+
claims_supported: z.array(z.string()).optional(),
|
|
12
|
+
claims_locales_supported: z.array(z.string()).optional(),
|
|
13
|
+
claims_parameter_supported: z.boolean().optional(),
|
|
14
|
+
request_parameter_supported: z.boolean().optional(),
|
|
15
|
+
request_uri_parameter_supported: z.boolean().optional(),
|
|
16
|
+
require_request_uri_registration: z.boolean().optional(),
|
|
17
|
+
scopes_supported: z.array(z.string()).optional(),
|
|
18
|
+
subject_types_supported: z.array(z.string()).optional(),
|
|
19
|
+
response_types_supported: z.array(z.string()).optional(),
|
|
20
|
+
response_modes_supported: z.array(z.string()).optional(),
|
|
21
|
+
grant_types_supported: z.array(z.string()).optional(),
|
|
22
|
+
code_challenge_methods_supported: z.array(z.string()).min(1).optional(),
|
|
23
|
+
ui_locales_supported: z.array(z.string()).optional(),
|
|
24
|
+
id_token_signing_alg_values_supported: z.array(z.string()).optional(),
|
|
25
|
+
display_values_supported: z.array(z.string()).optional(),
|
|
26
|
+
request_object_signing_alg_values_supported: z.array(z.string()).optional(),
|
|
27
|
+
authorization_response_iss_parameter_supported: z.boolean().optional(),
|
|
28
|
+
authorization_details_types_supported: z.array(z.string()).optional(),
|
|
29
|
+
request_object_encryption_alg_values_supported: z
|
|
30
|
+
.array(z.string())
|
|
31
|
+
.optional(),
|
|
32
|
+
request_object_encryption_enc_values_supported: z
|
|
33
|
+
.array(z.string())
|
|
34
|
+
.optional(),
|
|
35
|
+
|
|
36
|
+
jwks_uri: z.string().url().optional(),
|
|
37
|
+
|
|
38
|
+
authorization_endpoint: z.string().url(), // .optional(),
|
|
39
|
+
|
|
40
|
+
token_endpoint: z.string().url(), // .optional(),
|
|
41
|
+
token_endpoint_auth_methods_supported: z.array(z.string()).optional(),
|
|
42
|
+
token_endpoint_auth_signing_alg_values_supported: z
|
|
43
|
+
.array(z.string())
|
|
44
|
+
.optional(),
|
|
45
|
+
|
|
46
|
+
revocation_endpoint: z.string().url().optional(),
|
|
47
|
+
revocation_endpoint_auth_methods_supported: z.array(z.string()).optional(),
|
|
48
|
+
revocation_endpoint_auth_signing_alg_values_supported: z
|
|
49
|
+
.array(z.string())
|
|
50
|
+
.optional(),
|
|
51
|
+
|
|
52
|
+
introspection_endpoint: z.string().url().optional(),
|
|
53
|
+
introspection_endpoint_auth_methods_supported: z.array(z.string()).optional(),
|
|
54
|
+
introspection_endpoint_auth_signing_alg_values_supported: z
|
|
55
|
+
.array(z.string())
|
|
56
|
+
.optional(),
|
|
57
|
+
|
|
58
|
+
pushed_authorization_request_endpoint: z.string().url().optional(),
|
|
59
|
+
pushed_authorization_request_endpoint_auth_methods_supported: z
|
|
60
|
+
.array(z.string())
|
|
61
|
+
.optional(),
|
|
62
|
+
pushed_authorization_request_endpoint_auth_signing_alg_values_supported: z
|
|
63
|
+
.array(z.string())
|
|
64
|
+
.optional(),
|
|
65
|
+
|
|
66
|
+
require_pushed_authorization_requests: z.boolean().optional(),
|
|
67
|
+
|
|
68
|
+
userinfo_endpoint: z.string().url().optional(),
|
|
69
|
+
end_session_endpoint: z.string().url().optional(),
|
|
70
|
+
registration_endpoint: z.string().url().optional(),
|
|
71
|
+
|
|
72
|
+
// https://datatracker.ietf.org/doc/html/rfc9449#section-5.1
|
|
73
|
+
dpop_signing_alg_values_supported: z.array(z.string()).optional(),
|
|
74
|
+
|
|
75
|
+
// https://datatracker.ietf.org/doc/html/draft-ietf-oauth-resource-metadata-05#section-4
|
|
76
|
+
protected_resources: z.array(z.string().url()).optional(),
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
export type OAuthAuthorizationServerMetadata = z.infer<
|
|
80
|
+
typeof oauthAuthorizationServerMetadataSchema
|
|
81
|
+
>
|
|
82
|
+
|
|
83
|
+
export const oauthAuthorizationServerMetadataValidator =
|
|
84
|
+
oauthAuthorizationServerMetadataSchema
|
|
85
|
+
.superRefine((data, ctx) => {
|
|
86
|
+
if (
|
|
87
|
+
data.require_pushed_authorization_requests &&
|
|
88
|
+
!data.pushed_authorization_request_endpoint
|
|
89
|
+
) {
|
|
90
|
+
ctx.addIssue({
|
|
91
|
+
code: z.ZodIssueCode.custom,
|
|
92
|
+
message:
|
|
93
|
+
'"pushed_authorization_request_endpoint" required when "require_pushed_authorization_requests" is true',
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
.superRefine((data, ctx) => {
|
|
98
|
+
if (data.response_types_supported) {
|
|
99
|
+
if (!data.response_types_supported.includes('code')) {
|
|
100
|
+
ctx.addIssue({
|
|
101
|
+
code: z.ZodIssueCode.custom,
|
|
102
|
+
message: 'Response type "code" is required',
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { signedJwtSchema } from '@atproto/jwk'
|
|
3
|
+
|
|
4
|
+
import { oauthClientIdSchema } from './oauth-client-id.js'
|
|
5
|
+
import { CLIENT_ASSERTION_TYPE_JWT_BEARER } from './constants.js'
|
|
6
|
+
|
|
7
|
+
export const oauthClientCredentialsJwtBearerSchema = z.object({
|
|
8
|
+
client_id: oauthClientIdSchema,
|
|
9
|
+
client_assertion_type: z.literal(CLIENT_ASSERTION_TYPE_JWT_BEARER),
|
|
10
|
+
/**
|
|
11
|
+
* - "sub" the subject MUST be the "client_id" of the OAuth client
|
|
12
|
+
* - "iat" is required and MUST be less than one minute
|
|
13
|
+
* - "aud" must containing a value that identifies the authorization server
|
|
14
|
+
* - The JWT MAY contain a "jti" (JWT ID) claim that provides a unique identifier for the token.
|
|
15
|
+
* - Note that the authorization server may reject JWTs with an "exp" claim value that is unreasonably far in the future.
|
|
16
|
+
*
|
|
17
|
+
* @see {@link https://datatracker.ietf.org/doc/html/draft-ietf-oauth-jwt-bearer-11#section-3}
|
|
18
|
+
*/
|
|
19
|
+
client_assertion: signedJwtSchema,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
export const oauthClientCredentialsSecretPostSchema = z.object({
|
|
23
|
+
client_id: oauthClientIdSchema,
|
|
24
|
+
client_secret: z.string(),
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
export const oauthClientCredentialsSchema = z.union([
|
|
28
|
+
oauthClientCredentialsJwtBearerSchema,
|
|
29
|
+
oauthClientCredentialsSecretPostSchema,
|
|
30
|
+
])
|
|
31
|
+
|
|
32
|
+
export type OAuthClientCredentials = z.infer<
|
|
33
|
+
typeof oauthClientCredentialsSchema
|
|
34
|
+
>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { parseOAuthClientIdUrl } from './oauth-client-id-url.js'
|
|
2
|
+
import { OAuthClientId } from './oauth-client-id.js'
|
|
3
|
+
import { isIP } from './util.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @see {@link https://drafts.aaronpk.com/draft-parecki-oauth-client-id-metadata-document/draft-parecki-oauth-client-id-metadata-document.html}
|
|
7
|
+
*/
|
|
8
|
+
export type OAuthClientIdDiscoverable = OAuthClientId & `https://${string}`
|
|
9
|
+
|
|
10
|
+
export function isOAuthClientIdDiscoverable<C extends OAuthClientId>(
|
|
11
|
+
clientId: C,
|
|
12
|
+
): clientId is C & OAuthClientIdDiscoverable {
|
|
13
|
+
try {
|
|
14
|
+
parseOAuthDiscoverableClientId(clientId)
|
|
15
|
+
return true
|
|
16
|
+
} catch {
|
|
17
|
+
return false
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function parseOAuthDiscoverableClientId(clientId: OAuthClientId): URL {
|
|
22
|
+
const url = parseOAuthClientIdUrl(clientId)
|
|
23
|
+
|
|
24
|
+
// Optimization: cheap checks first
|
|
25
|
+
|
|
26
|
+
if (url.hostname === 'localhost') {
|
|
27
|
+
throw new TypeError('ClientID must not be a loopback hostname')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (url.protocol !== 'https:') {
|
|
31
|
+
throw new TypeError('ClientID must use the "https:" protocol')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (url.hash) {
|
|
35
|
+
throw new TypeError('ClientID must not contain a fragment')
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (url.username || url.password) {
|
|
39
|
+
throw new TypeError('ClientID must not contain credentials')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (url.pathname === '/') {
|
|
43
|
+
throw new TypeError(
|
|
44
|
+
'ClientID must contain a path (e.g. "/client-metadata")',
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (url.pathname !== '/' && url.pathname.endsWith('/')) {
|
|
49
|
+
throw new TypeError('ClientID must not end with a trailing slash')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (url.pathname.includes('//')) {
|
|
53
|
+
throw new TypeError(
|
|
54
|
+
`ClientID must not contain any double slashes in its path`,
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Note: Query string is allowed
|
|
59
|
+
// Note: no restriction on the port for non-loopback URIs
|
|
60
|
+
|
|
61
|
+
if (isIP(url.hostname)) {
|
|
62
|
+
throw new TypeError('ClientID must not be an IP address')
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return url
|
|
66
|
+
}
|