@atcute/oauth-types 0.1.0 → 1.0.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/README.md +6 -5
- package/dist/build-client-metadata.d.ts +18 -160
- package/dist/build-client-metadata.d.ts.map +1 -1
- package/dist/build-client-metadata.js +73 -3
- package/dist/build-client-metadata.js.map +1 -1
- package/dist/index.d.ts +31 -30
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/schemas/atcute-client-shared.d.ts +8 -0
- package/dist/schemas/atcute-client-shared.d.ts.map +1 -0
- package/dist/schemas/atcute-client-shared.js +15 -0
- package/dist/schemas/atcute-client-shared.js.map +1 -0
- package/dist/schemas/atcute-confidential-client-metadata.d.ts +228 -4
- package/dist/schemas/atcute-confidential-client-metadata.d.ts.map +1 -1
- package/dist/schemas/atcute-confidential-client-metadata.js +48 -88
- package/dist/schemas/atcute-confidential-client-metadata.js.map +1 -1
- package/dist/schemas/atcute-public-client-metadata.d.ts +95 -0
- package/dist/schemas/atcute-public-client-metadata.d.ts.map +1 -0
- package/dist/schemas/atcute-public-client-metadata.js +74 -0
- package/dist/schemas/atcute-public-client-metadata.js.map +1 -0
- package/dist/schemas/atproto-authorization-server-metadata.d.ts +786 -4
- package/dist/schemas/atproto-authorization-server-metadata.d.ts.map +1 -1
- package/dist/schemas/atproto-authorization-server-metadata.js +2 -18
- package/dist/schemas/atproto-authorization-server-metadata.js.map +1 -1
- package/dist/schemas/atproto-oauth-scope.d.ts +3 -3
- package/dist/schemas/atproto-oauth-scope.d.ts.map +1 -1
- package/dist/schemas/atproto-oauth-scope.js +2 -2
- package/dist/schemas/atproto-oauth-scope.js.map +1 -1
- package/dist/schemas/atproto-oauth-token-response.d.ts +17 -17
- package/dist/schemas/atproto-oauth-token-response.d.ts.map +1 -1
- package/dist/schemas/atproto-oauth-token-response.js +6 -6
- package/dist/schemas/atproto-oauth-token-response.js.map +1 -1
- package/dist/schemas/atproto-protected-resource-metadata.d.ts +100 -4
- package/dist/schemas/atproto-protected-resource-metadata.d.ts.map +1 -1
- package/dist/schemas/atproto-protected-resource-metadata.js +2 -11
- package/dist/schemas/atproto-protected-resource-metadata.js.map +1 -1
- package/dist/schemas/jwk.d.ts +4289 -42
- package/dist/schemas/jwk.d.ts.map +1 -1
- package/dist/schemas/jwk.js +58 -91
- package/dist/schemas/jwk.js.map +1 -1
- package/dist/schemas/jwks.d.ts +87 -42
- package/dist/schemas/jwks.d.ts.map +1 -1
- package/dist/schemas/jwks.js +13 -29
- package/dist/schemas/jwks.js.map +1 -1
- package/dist/schemas/oauth-authorization-details.d.ts +18 -18
- package/dist/schemas/oauth-authorization-details.d.ts.map +1 -1
- package/dist/schemas/oauth-authorization-details.js +7 -7
- package/dist/schemas/oauth-authorization-details.js.map +1 -1
- package/dist/schemas/oauth-authorization-server-metadata.d.ts +462 -48
- package/dist/schemas/oauth-authorization-server-metadata.d.ts.map +1 -1
- package/dist/schemas/oauth-authorization-server-metadata.js +46 -65
- package/dist/schemas/oauth-authorization-server-metadata.js.map +1 -1
- package/dist/schemas/oauth-client-id-discoverable.d.ts +2 -2
- package/dist/schemas/oauth-client-id-discoverable.d.ts.map +1 -1
- package/dist/schemas/oauth-client-id-discoverable.js +20 -22
- package/dist/schemas/oauth-client-id-discoverable.js.map +1 -1
- package/dist/schemas/oauth-client-id.d.ts +3 -3
- package/dist/schemas/oauth-client-id.d.ts.map +1 -1
- package/dist/schemas/oauth-client-id.js +2 -2
- package/dist/schemas/oauth-client-id.js.map +1 -1
- package/dist/schemas/oauth-client-metadata.d.ts +73 -51
- package/dist/schemas/oauth-client-metadata.d.ts.map +1 -1
- package/dist/schemas/oauth-client-metadata.js +33 -40
- package/dist/schemas/oauth-client-metadata.js.map +1 -1
- package/dist/schemas/oauth-code-challenge-method.d.ts +3 -3
- package/dist/schemas/oauth-code-challenge-method.d.ts.map +1 -1
- package/dist/schemas/oauth-code-challenge-method.js +2 -2
- package/dist/schemas/oauth-code-challenge-method.js.map +1 -1
- package/dist/schemas/oauth-endpoint-auth-method.d.ts +3 -3
- package/dist/schemas/oauth-endpoint-auth-method.d.ts.map +1 -1
- package/dist/schemas/oauth-endpoint-auth-method.js +10 -2
- package/dist/schemas/oauth-endpoint-auth-method.js.map +1 -1
- package/dist/schemas/oauth-grant-type.d.ts +3 -3
- package/dist/schemas/oauth-grant-type.d.ts.map +1 -1
- package/dist/schemas/oauth-grant-type.js +10 -3
- package/dist/schemas/oauth-grant-type.js.map +1 -1
- package/dist/schemas/oauth-issuer-identifier.d.ts +3 -3
- package/dist/schemas/oauth-issuer-identifier.d.ts.map +1 -1
- package/dist/schemas/oauth-issuer-identifier.js +16 -9
- package/dist/schemas/oauth-issuer-identifier.js.map +1 -1
- package/dist/schemas/oauth-par-response.d.ts +5 -5
- package/dist/schemas/oauth-par-response.d.ts.map +1 -1
- package/dist/schemas/oauth-par-response.js +3 -3
- package/dist/schemas/oauth-par-response.js.map +1 -1
- package/dist/schemas/oauth-prompt.d.ts +3 -3
- package/dist/schemas/oauth-prompt.d.ts.map +1 -1
- package/dist/schemas/oauth-prompt.js +2 -2
- package/dist/schemas/oauth-prompt.js.map +1 -1
- package/dist/schemas/oauth-protected-resource-metadata.d.ts +88 -16
- package/dist/schemas/oauth-protected-resource-metadata.d.ts.map +1 -1
- package/dist/schemas/oauth-protected-resource-metadata.js +14 -26
- package/dist/schemas/oauth-protected-resource-metadata.js.map +1 -1
- package/dist/schemas/oauth-redirect-uri.d.ts +5 -5
- package/dist/schemas/oauth-redirect-uri.d.ts.map +1 -1
- package/dist/schemas/oauth-redirect-uri.js +3 -16
- package/dist/schemas/oauth-redirect-uri.js.map +1 -1
- package/dist/schemas/oauth-response-mode.d.ts +3 -3
- package/dist/schemas/oauth-response-mode.d.ts.map +1 -1
- package/dist/schemas/oauth-response-mode.js +2 -2
- package/dist/schemas/oauth-response-mode.js.map +1 -1
- package/dist/schemas/oauth-response-type.d.ts +3 -3
- package/dist/schemas/oauth-response-type.d.ts.map +1 -1
- package/dist/schemas/oauth-response-type.js +13 -7
- package/dist/schemas/oauth-response-type.js.map +1 -1
- package/dist/schemas/oauth-scope.d.ts +3 -3
- package/dist/schemas/oauth-scope.d.ts.map +1 -1
- package/dist/schemas/oauth-scope.js +2 -2
- package/dist/schemas/oauth-scope.js.map +1 -1
- package/dist/schemas/oauth-token-response.d.ts +17 -17
- package/dist/schemas/oauth-token-response.d.ts.map +1 -1
- package/dist/schemas/oauth-token-response.js +7 -7
- package/dist/schemas/oauth-token-response.js.map +1 -1
- package/dist/schemas/oauth-token-type.d.ts +3 -3
- package/dist/schemas/oauth-token-type.d.ts.map +1 -1
- package/dist/schemas/oauth-token-type.js +8 -7
- package/dist/schemas/oauth-token-type.js.map +1 -1
- package/dist/schemas/uri.d.ts +7 -7
- package/dist/schemas/uri.d.ts.map +1 -1
- package/dist/schemas/uri.js +44 -44
- package/dist/schemas/uri.js.map +1 -1
- package/dist/schemas/utils.d.ts.map +1 -1
- package/dist/schemas/utils.js.map +1 -1
- package/dist/scope.d.ts.map +1 -1
- package/dist/scope.js.map +1 -1
- package/lib/build-client-metadata.ts +92 -6
- package/lib/index.ts +38 -30
- package/lib/schemas/atcute-client-shared.ts +25 -0
- package/lib/schemas/atcute-confidential-client-metadata.ts +81 -111
- package/lib/schemas/atcute-public-client-metadata.ts +101 -0
- package/lib/schemas/atproto-authorization-server-metadata.ts +22 -23
- package/lib/schemas/atproto-oauth-scope.ts +8 -5
- package/lib/schemas/atproto-oauth-token-response.ts +10 -9
- package/lib/schemas/atproto-protected-resource-metadata.ts +15 -15
- package/lib/schemas/jwk.ts +104 -120
- package/lib/schemas/jwks.ts +28 -40
- package/lib/schemas/oauth-authorization-details.ts +10 -10
- package/lib/schemas/oauth-authorization-server-metadata.ts +72 -74
- package/lib/schemas/oauth-client-id-discoverable.ts +43 -48
- package/lib/schemas/oauth-client-id.ts +3 -3
- package/lib/schemas/oauth-client-metadata.ts +45 -49
- package/lib/schemas/oauth-code-challenge-method.ts +3 -3
- package/lib/schemas/oauth-endpoint-auth-method.ts +11 -11
- package/lib/schemas/oauth-grant-type.ts +11 -11
- package/lib/schemas/oauth-issuer-identifier.ts +35 -27
- package/lib/schemas/oauth-par-response.ts +4 -4
- package/lib/schemas/oauth-prompt.ts +3 -9
- package/lib/schemas/oauth-protected-resource-metadata.ts +26 -35
- package/lib/schemas/oauth-redirect-uri.ts +15 -23
- package/lib/schemas/oauth-response-mode.ts +3 -7
- package/lib/schemas/oauth-response-type.ts +12 -12
- package/lib/schemas/oauth-scope.ts +3 -3
- package/lib/schemas/oauth-token-response.ts +10 -10
- package/lib/schemas/oauth-token-type.ts +16 -12
- package/lib/schemas/uri.ts +89 -76
- package/package.json +9 -8
|
@@ -1,101 +1,99 @@
|
|
|
1
|
-
import * as v from '
|
|
1
|
+
import * as v from 'valibot';
|
|
2
2
|
|
|
3
|
-
import { oauthCodeChallengeMethodSchema } from './oauth-code-challenge-method.
|
|
4
|
-
import { oauthIssuerIdentifierSchema } from './oauth-issuer-identifier.
|
|
5
|
-
import { oauthPromptSchema } from './oauth-prompt.
|
|
6
|
-
import { webUriSchema } from './uri.
|
|
3
|
+
import { oauthCodeChallengeMethodSchema } from './oauth-code-challenge-method.ts';
|
|
4
|
+
import { oauthIssuerIdentifierSchema } from './oauth-issuer-identifier.ts';
|
|
5
|
+
import { oauthPromptSchema } from './oauth-prompt.ts';
|
|
6
|
+
import { webUriSchema } from './uri.ts';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @see {@link https://datatracker.ietf.org/doc/html/rfc8414}
|
|
10
10
|
*/
|
|
11
|
-
export const oauthAuthorizationServerMetadataSchema = v.
|
|
11
|
+
export const oauthAuthorizationServerMetadataSchema = v.looseObject({
|
|
12
12
|
issuer: oauthIssuerIdentifierSchema,
|
|
13
13
|
|
|
14
|
-
claims_supported: v.array(v.string())
|
|
15
|
-
claims_locales_supported: v.array(v.string())
|
|
16
|
-
claims_parameter_supported: v.
|
|
17
|
-
request_parameter_supported: v.
|
|
18
|
-
request_uri_parameter_supported: v.
|
|
19
|
-
require_request_uri_registration: v.
|
|
20
|
-
scopes_supported: v.array(v.string())
|
|
21
|
-
subject_types_supported: v.array(v.string())
|
|
22
|
-
response_types_supported: v.array(v.string())
|
|
23
|
-
response_modes_supported: v.array(v.string())
|
|
24
|
-
grant_types_supported: v.array(v.string())
|
|
25
|
-
code_challenge_methods_supported: v.array(oauthCodeChallengeMethodSchema)
|
|
26
|
-
ui_locales_supported: v.array(v.string())
|
|
27
|
-
id_token_signing_alg_values_supported: v.array(v.string())
|
|
28
|
-
display_values_supported: v.array(v.string())
|
|
29
|
-
prompt_values_supported: v.array(oauthPromptSchema)
|
|
30
|
-
request_object_signing_alg_values_supported: v.array(v.string())
|
|
31
|
-
authorization_response_iss_parameter_supported: v.
|
|
32
|
-
authorization_details_types_supported: v.array(v.string())
|
|
33
|
-
request_object_encryption_alg_values_supported: v.array(v.string())
|
|
34
|
-
request_object_encryption_enc_values_supported: v.array(v.string())
|
|
35
|
-
|
|
36
|
-
jwks_uri:
|
|
14
|
+
claims_supported: v.optional(v.array(v.string())),
|
|
15
|
+
claims_locales_supported: v.optional(v.array(v.string())),
|
|
16
|
+
claims_parameter_supported: v.optional(v.boolean()),
|
|
17
|
+
request_parameter_supported: v.optional(v.boolean()),
|
|
18
|
+
request_uri_parameter_supported: v.optional(v.boolean()),
|
|
19
|
+
require_request_uri_registration: v.optional(v.boolean()),
|
|
20
|
+
scopes_supported: v.optional(v.array(v.string())),
|
|
21
|
+
subject_types_supported: v.optional(v.array(v.string())),
|
|
22
|
+
response_types_supported: v.optional(v.array(v.string())),
|
|
23
|
+
response_modes_supported: v.optional(v.array(v.string())),
|
|
24
|
+
grant_types_supported: v.optional(v.array(v.string())),
|
|
25
|
+
code_challenge_methods_supported: v.optional(v.array(oauthCodeChallengeMethodSchema)),
|
|
26
|
+
ui_locales_supported: v.optional(v.array(v.string())),
|
|
27
|
+
id_token_signing_alg_values_supported: v.optional(v.array(v.string())),
|
|
28
|
+
display_values_supported: v.optional(v.array(v.string())),
|
|
29
|
+
prompt_values_supported: v.optional(v.array(oauthPromptSchema)),
|
|
30
|
+
request_object_signing_alg_values_supported: v.optional(v.array(v.string())),
|
|
31
|
+
authorization_response_iss_parameter_supported: v.optional(v.boolean()),
|
|
32
|
+
authorization_details_types_supported: v.optional(v.array(v.string())),
|
|
33
|
+
request_object_encryption_alg_values_supported: v.optional(v.array(v.string())),
|
|
34
|
+
request_object_encryption_enc_values_supported: v.optional(v.array(v.string())),
|
|
35
|
+
|
|
36
|
+
jwks_uri: v.optional(webUriSchema),
|
|
37
37
|
|
|
38
38
|
authorization_endpoint: webUriSchema,
|
|
39
39
|
|
|
40
40
|
token_endpoint: webUriSchema,
|
|
41
41
|
// https://www.rfc-editor.org/rfc/rfc8414.html#section-2
|
|
42
|
-
token_endpoint_auth_methods_supported: v.array(v.string())
|
|
43
|
-
token_endpoint_auth_signing_alg_values_supported: v.array(v.string())
|
|
42
|
+
token_endpoint_auth_methods_supported: v.optional(v.array(v.string())),
|
|
43
|
+
token_endpoint_auth_signing_alg_values_supported: v.optional(v.array(v.string())),
|
|
44
44
|
|
|
45
|
-
revocation_endpoint:
|
|
46
|
-
revocation_endpoint_auth_methods_supported: v.array(v.string())
|
|
47
|
-
revocation_endpoint_auth_signing_alg_values_supported: v.array(v.string())
|
|
45
|
+
revocation_endpoint: v.optional(webUriSchema),
|
|
46
|
+
revocation_endpoint_auth_methods_supported: v.optional(v.array(v.string())),
|
|
47
|
+
revocation_endpoint_auth_signing_alg_values_supported: v.optional(v.array(v.string())),
|
|
48
48
|
|
|
49
|
-
introspection_endpoint:
|
|
50
|
-
introspection_endpoint_auth_methods_supported: v.array(v.string())
|
|
51
|
-
introspection_endpoint_auth_signing_alg_values_supported: v.array(v.string())
|
|
49
|
+
introspection_endpoint: v.optional(webUriSchema),
|
|
50
|
+
introspection_endpoint_auth_methods_supported: v.optional(v.array(v.string())),
|
|
51
|
+
introspection_endpoint_auth_signing_alg_values_supported: v.optional(v.array(v.string())),
|
|
52
52
|
|
|
53
|
-
pushed_authorization_request_endpoint:
|
|
54
|
-
pushed_authorization_request_endpoint_auth_methods_supported: v.array(v.string())
|
|
55
|
-
pushed_authorization_request_endpoint_auth_signing_alg_values_supported: v.array(v.string())
|
|
56
|
-
require_pushed_authorization_requests: v.
|
|
53
|
+
pushed_authorization_request_endpoint: v.optional(webUriSchema),
|
|
54
|
+
pushed_authorization_request_endpoint_auth_methods_supported: v.optional(v.array(v.string())),
|
|
55
|
+
pushed_authorization_request_endpoint_auth_signing_alg_values_supported: v.optional(v.array(v.string())),
|
|
56
|
+
require_pushed_authorization_requests: v.optional(v.boolean()),
|
|
57
57
|
|
|
58
|
-
userinfo_endpoint:
|
|
59
|
-
end_session_endpoint:
|
|
60
|
-
registration_endpoint:
|
|
58
|
+
userinfo_endpoint: v.optional(webUriSchema),
|
|
59
|
+
end_session_endpoint: v.optional(webUriSchema),
|
|
60
|
+
registration_endpoint: v.optional(webUriSchema),
|
|
61
61
|
|
|
62
62
|
// https://datatracker.ietf.org/doc/html/rfc9449#section-5.1
|
|
63
|
-
dpop_signing_alg_values_supported: v.array(v.string())
|
|
63
|
+
dpop_signing_alg_values_supported: v.optional(v.array(v.string())),
|
|
64
64
|
|
|
65
65
|
// https://www.rfc-editor.org/rfc/rfc9728.html#section-4
|
|
66
|
-
protected_resources: v.array(webUriSchema)
|
|
66
|
+
protected_resources: v.optional(v.array(webUriSchema)),
|
|
67
67
|
|
|
68
68
|
// https://www.ietf.org/archive/id/draft-ietf-oauth-client-id-metadata-document-00.html
|
|
69
|
-
client_id_metadata_document_supported: v.
|
|
69
|
+
client_id_metadata_document_supported: v.optional(v.boolean()),
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
export type OAuthAuthorizationServerMetadata = v.
|
|
73
|
-
|
|
74
|
-
export const oauthAuthorizationServerMetadataValidator =
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
72
|
+
export type OAuthAuthorizationServerMetadata = v.InferOutput<typeof oauthAuthorizationServerMetadataSchema>;
|
|
73
|
+
|
|
74
|
+
export const oauthAuthorizationServerMetadataValidator = v.pipe(
|
|
75
|
+
oauthAuthorizationServerMetadataSchema,
|
|
76
|
+
v.forward(
|
|
77
|
+
v.check(
|
|
78
|
+
(data) => !data.require_pushed_authorization_requests || !!data.pushed_authorization_request_endpoint,
|
|
79
|
+
`"pushed_authorization_request_endpoint" required when "require_pushed_authorization_requests" is true`,
|
|
80
|
+
),
|
|
81
|
+
['pushed_authorization_request_endpoint'],
|
|
82
|
+
),
|
|
83
|
+
v.forward(
|
|
84
|
+
v.check(
|
|
85
|
+
(data) => !data.response_types_supported || data.response_types_supported.includes('code'),
|
|
86
|
+
`response type "code" is required`,
|
|
87
|
+
),
|
|
88
|
+
['response_types_supported'],
|
|
89
|
+
),
|
|
90
|
+
v.forward(
|
|
91
|
+
v.check(
|
|
92
|
+
(data) => !data.token_endpoint_auth_signing_alg_values_supported?.includes('none'),
|
|
91
93
|
// https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3
|
|
92
94
|
// > The value `none` MUST NOT be used.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return v.ok(data);
|
|
100
|
-
},
|
|
95
|
+
`client authentication method "none" is not allowed`,
|
|
96
|
+
),
|
|
97
|
+
['token_endpoint_auth_signing_alg_values_supported'],
|
|
98
|
+
),
|
|
101
99
|
);
|
|
@@ -1,53 +1,48 @@
|
|
|
1
|
-
import * as v from '
|
|
1
|
+
import * as v from 'valibot';
|
|
2
2
|
|
|
3
|
-
import { oauthClientIdSchema } from './oauth-client-id.
|
|
4
|
-
import { httpsUriSchema } from './uri.
|
|
5
|
-
import { extractUrlPath, isHostnameIP } from './utils.
|
|
3
|
+
import { oauthClientIdSchema } from './oauth-client-id.ts';
|
|
4
|
+
import { httpsUriSchema } from './uri.ts';
|
|
5
|
+
import { extractUrlPath, isHostnameIP } from './utils.ts';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @see {@link https://www.ietf.org/archive/id/draft-ietf-oauth-client-id-metadata-document-00.html}
|
|
9
9
|
*/
|
|
10
|
-
export const oauthClientIdDiscoverableSchema = v.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return v.err(`client ID must be in canonical form ("${url.href}", got "${input}")`);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return v.ok(input);
|
|
53
|
-
});
|
|
10
|
+
export const oauthClientIdDiscoverableSchema = v.pipe(
|
|
11
|
+
oauthClientIdSchema,
|
|
12
|
+
httpsUriSchema,
|
|
13
|
+
v.rawCheck(({ dataset, addIssue }) => {
|
|
14
|
+
if (!dataset.typed) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const input = dataset.value;
|
|
18
|
+
const url = new URL(input);
|
|
19
|
+
|
|
20
|
+
if (url.username || url.password) {
|
|
21
|
+
addIssue({ message: `client ID must not contain credentials` });
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (url.hash) {
|
|
25
|
+
addIssue({ message: `client ID must not contain a fragment` });
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (url.pathname === '/') {
|
|
29
|
+
addIssue({ message: `client ID must contain a path component (e.g. "/client-metadata.json")` });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (url.pathname.endsWith('/')) {
|
|
33
|
+
addIssue({ message: `client ID path must not end with a trailing slash` });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (isHostnameIP(url.hostname)) {
|
|
37
|
+
addIssue({ message: `client ID hostname must not be an IP address` });
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// URL constructor normalizes the URL, so we extract the path manually to avoid
|
|
42
|
+
// normalization, then compare it to the normalized path to ensure that the URL does not
|
|
43
|
+
// contain path traversal or other unexpected characters
|
|
44
|
+
if (extractUrlPath(input) !== url.pathname) {
|
|
45
|
+
addIssue({ message: `client ID must be in canonical form ("${url.href}", got "${input}")` });
|
|
46
|
+
}
|
|
47
|
+
}),
|
|
48
|
+
);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as v from '
|
|
1
|
+
import * as v from 'valibot';
|
|
2
2
|
|
|
3
3
|
/** base OAuth client ID (any non-empty string) */
|
|
4
|
-
export const oauthClientIdSchema = v.
|
|
4
|
+
export const oauthClientIdSchema = v.pipe(v.string(), v.nonEmpty(`must not be empty`));
|
|
5
5
|
|
|
6
|
-
export type OAuthClientId = v.
|
|
6
|
+
export type OAuthClientId = v.InferOutput<typeof oauthClientIdSchema>;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import * as v from '
|
|
1
|
+
import * as v from 'valibot';
|
|
2
2
|
|
|
3
|
-
import { jwksPubSchema } from './jwks.
|
|
4
|
-
import { oauthClientIdSchema } from './oauth-client-id.
|
|
5
|
-
import { oauthEndpointAuthMethodSchema } from './oauth-endpoint-auth-method.
|
|
6
|
-
import { oauthGrantTypeSchema } from './oauth-grant-type.
|
|
7
|
-
import { oauthRedirectUriSchema } from './oauth-redirect-uri.
|
|
8
|
-
import { oauthResponseTypeSchema } from './oauth-response-type.
|
|
9
|
-
import { oauthScopeSchema } from './oauth-scope.
|
|
10
|
-
import { webUriSchema } from './uri.
|
|
3
|
+
import { jwksPubSchema } from './jwks.ts';
|
|
4
|
+
import { oauthClientIdSchema } from './oauth-client-id.ts';
|
|
5
|
+
import { oauthEndpointAuthMethodSchema } from './oauth-endpoint-auth-method.ts';
|
|
6
|
+
import { oauthGrantTypeSchema } from './oauth-grant-type.ts';
|
|
7
|
+
import { oauthRedirectUriSchema } from './oauth-redirect-uri.ts';
|
|
8
|
+
import { oauthResponseTypeSchema } from './oauth-response-type.ts';
|
|
9
|
+
import { oauthScopeSchema } from './oauth-scope.ts';
|
|
10
|
+
import { webUriSchema } from './uri.ts';
|
|
11
11
|
|
|
12
|
-
const oauthApplicationTypeSchema = v.
|
|
12
|
+
const oauthApplicationTypeSchema = v.picklist(['web', 'native']);
|
|
13
13
|
|
|
14
|
-
const oauthSubjectTypeSchema = v.
|
|
14
|
+
const oauthSubjectTypeSchema = v.picklist(['public', 'pairwise']);
|
|
15
15
|
|
|
16
16
|
// simple email validation
|
|
17
17
|
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
@@ -22,44 +22,40 @@ const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
|
22
22
|
* @see {@link https://openid.net/specs/openid-connect-registration-1_0.html}
|
|
23
23
|
* @see {@link https://datatracker.ietf.org/doc/html/rfc7591}
|
|
24
24
|
*/
|
|
25
|
-
export const oauthClientMetadataSchema = v.
|
|
25
|
+
export const oauthClientMetadataSchema = v.looseObject({
|
|
26
26
|
// https://www.rfc-editor.org/rfc/rfc7591.html#section-2
|
|
27
|
-
redirect_uris: v
|
|
28
|
-
.array(oauthRedirectUriSchema)
|
|
29
|
-
.
|
|
30
|
-
|
|
27
|
+
redirect_uris: v.pipe(
|
|
28
|
+
v.array(oauthRedirectUriSchema),
|
|
29
|
+
v.minLength(1, `must have at least one redirect URI`),
|
|
30
|
+
),
|
|
31
|
+
response_types: v.optional(v.array(oauthResponseTypeSchema)),
|
|
31
32
|
// > If omitted, the default is that the client will use only the "code"
|
|
32
33
|
// > response type.
|
|
33
|
-
|
|
34
|
-
grant_types: v.array(oauthGrantTypeSchema).optional(),
|
|
34
|
+
grant_types: v.optional(v.array(oauthGrantTypeSchema)),
|
|
35
35
|
// > If omitted, the default behavior is that the client will use only the
|
|
36
36
|
// > "authorization_code" Grant Type.
|
|
37
|
-
|
|
38
|
-
scope: oauthScopeSchema.optional(),
|
|
37
|
+
scope: v.optional(oauthScopeSchema),
|
|
39
38
|
// https://www.rfc-editor.org/rfc/rfc7591.html#section-2
|
|
40
|
-
token_endpoint_auth_method:
|
|
39
|
+
token_endpoint_auth_method: v.optional(oauthEndpointAuthMethodSchema),
|
|
41
40
|
// > If unspecified or omitted, the default is "client_secret_basic" [...].
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
policy_uri: webUriSchema.optional(),
|
|
61
|
-
tos_uri: webUriSchema.optional(),
|
|
62
|
-
logo_uri: webUriSchema.optional(),
|
|
41
|
+
token_endpoint_auth_signing_alg: v.optional(v.string()),
|
|
42
|
+
userinfo_signed_response_alg: v.optional(v.string()),
|
|
43
|
+
userinfo_encrypted_response_alg: v.optional(v.string()),
|
|
44
|
+
jwks_uri: v.optional(webUriSchema),
|
|
45
|
+
jwks: v.optional(jwksPubSchema),
|
|
46
|
+
application_type: v.optional(oauthApplicationTypeSchema),
|
|
47
|
+
subject_type: v.optional(oauthSubjectTypeSchema),
|
|
48
|
+
request_object_signing_alg: v.optional(v.string()),
|
|
49
|
+
id_token_signed_response_alg: v.optional(v.string()),
|
|
50
|
+
authorization_signed_response_alg: v.optional(v.string()),
|
|
51
|
+
authorization_encrypted_response_enc: v.optional(v.literal('A128CBC-HS256')),
|
|
52
|
+
authorization_encrypted_response_alg: v.optional(v.string()),
|
|
53
|
+
client_id: v.optional(oauthClientIdSchema),
|
|
54
|
+
client_name: v.optional(v.string()),
|
|
55
|
+
client_uri: v.optional(webUriSchema),
|
|
56
|
+
policy_uri: v.optional(webUriSchema),
|
|
57
|
+
tos_uri: v.optional(webUriSchema),
|
|
58
|
+
logo_uri: v.optional(webUriSchema),
|
|
63
59
|
|
|
64
60
|
/**
|
|
65
61
|
* default Maximum Authentication Age. specifies that the End-User MUST be
|
|
@@ -68,16 +64,16 @@ export const oauthClientMetadataSchema = v.object({
|
|
|
68
64
|
* this default value. if omitted, no default Maximum Authentication Age is
|
|
69
65
|
* specified.
|
|
70
66
|
*/
|
|
71
|
-
default_max_age: v.
|
|
72
|
-
require_auth_time: v.
|
|
73
|
-
contacts: v.array(v.
|
|
74
|
-
tls_client_certificate_bound_access_tokens: v.
|
|
67
|
+
default_max_age: v.optional(v.number()),
|
|
68
|
+
require_auth_time: v.optional(v.boolean()),
|
|
69
|
+
contacts: v.optional(v.array(v.pipe(v.string(), v.regex(EMAIL_RE, `must be a valid email`)))),
|
|
70
|
+
tls_client_certificate_bound_access_tokens: v.optional(v.boolean()),
|
|
75
71
|
|
|
76
72
|
// https://datatracker.ietf.org/doc/html/rfc9449#section-5.2
|
|
77
|
-
dpop_bound_access_tokens: v.
|
|
73
|
+
dpop_bound_access_tokens: v.optional(v.boolean()),
|
|
78
74
|
|
|
79
75
|
// https://datatracker.ietf.org/doc/html/rfc9396#section-14.5
|
|
80
|
-
authorization_details_types: v.array(v.string())
|
|
76
|
+
authorization_details_types: v.optional(v.array(v.string())),
|
|
81
77
|
});
|
|
82
78
|
|
|
83
|
-
export type OAuthClientMetadata = v.
|
|
79
|
+
export type OAuthClientMetadata = v.InferOutput<typeof oauthClientMetadataSchema>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as v from '
|
|
1
|
+
import * as v from 'valibot';
|
|
2
2
|
|
|
3
|
-
export const oauthCodeChallengeMethodSchema = v.
|
|
3
|
+
export const oauthCodeChallengeMethodSchema = v.picklist(['S256', 'plain']);
|
|
4
4
|
|
|
5
|
-
export type OAuthCodeChallengeMethod = v.
|
|
5
|
+
export type OAuthCodeChallengeMethod = v.InferOutput<typeof oauthCodeChallengeMethodSchema>;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import * as v from '
|
|
1
|
+
import * as v from 'valibot';
|
|
2
2
|
|
|
3
|
-
export const oauthEndpointAuthMethodSchema = v.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
);
|
|
3
|
+
export const oauthEndpointAuthMethodSchema = v.picklist([
|
|
4
|
+
'client_secret_basic',
|
|
5
|
+
'client_secret_jwt',
|
|
6
|
+
'client_secret_post',
|
|
7
|
+
'none',
|
|
8
|
+
'private_key_jwt',
|
|
9
|
+
'self_signed_tls_client_auth',
|
|
10
|
+
'tls_client_auth',
|
|
11
|
+
]);
|
|
12
12
|
|
|
13
|
-
export type OAuthEndpointAuthMethod = v.
|
|
13
|
+
export type OAuthEndpointAuthMethod = v.InferOutput<typeof oauthEndpointAuthMethodSchema>;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import * as v from '
|
|
1
|
+
import * as v from 'valibot';
|
|
2
2
|
|
|
3
|
-
export const oauthGrantTypeSchema = v.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
);
|
|
3
|
+
export const oauthGrantTypeSchema = v.picklist([
|
|
4
|
+
'authorization_code',
|
|
5
|
+
'implicit',
|
|
6
|
+
'refresh_token',
|
|
7
|
+
'password', // not part of OAuth 2.1
|
|
8
|
+
'client_credentials',
|
|
9
|
+
'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
|
10
|
+
'urn:ietf:params:oauth:grant-type:saml2-bearer',
|
|
11
|
+
]);
|
|
12
12
|
|
|
13
|
-
export type OAuthGrantType = v.
|
|
13
|
+
export type OAuthGrantType = v.InferOutput<typeof oauthGrantTypeSchema>;
|
|
@@ -1,30 +1,38 @@
|
|
|
1
|
-
import * as v from '
|
|
1
|
+
import * as v from 'valibot';
|
|
2
2
|
|
|
3
|
-
import { webUriSchema } from './uri.
|
|
3
|
+
import { webUriSchema } from './uri.ts';
|
|
4
4
|
|
|
5
|
-
export const oauthIssuerIdentifierSchema =
|
|
5
|
+
export const oauthIssuerIdentifierSchema = v.pipe(
|
|
6
|
+
webUriSchema,
|
|
6
7
|
// validate the issuer (MIX-UP attacks)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
8
|
+
v.rawCheck(({ dataset, addIssue }) => {
|
|
9
|
+
if (!dataset.typed) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const input = dataset.value;
|
|
13
|
+
|
|
14
|
+
if (input.endsWith('/')) {
|
|
15
|
+
addIssue({ message: `issuer URL must not end with a slash` });
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const url = new URL(input);
|
|
20
|
+
|
|
21
|
+
if (url.username || url.password) {
|
|
22
|
+
addIssue({ message: `issuer URL must not contain a username or password` });
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (url.hash || url.search) {
|
|
27
|
+
addIssue({ message: `issuer URL must not contain a query or fragment` });
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const canonicalValue = url.pathname === '/' ? url.origin : url.href;
|
|
32
|
+
if (input !== canonicalValue) {
|
|
33
|
+
addIssue({ message: `issuer URL must be in the canonical form` });
|
|
34
|
+
}
|
|
35
|
+
}),
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
export type OAuthIssuerIdentifier = v.InferOutput<typeof oauthIssuerIdentifierSchema>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import * as v from '
|
|
1
|
+
import * as v from 'valibot';
|
|
2
2
|
|
|
3
3
|
const isPositiveInteger = (n: number): boolean => Number.isInteger(n) && n > 0;
|
|
4
4
|
|
|
5
|
-
export const oauthParResponseSchema = v.
|
|
5
|
+
export const oauthParResponseSchema = v.looseObject({
|
|
6
6
|
request_uri: v.string(),
|
|
7
|
-
expires_in: v.number().
|
|
7
|
+
expires_in: v.pipe(v.number(), v.check(isPositiveInteger, `must be a positive integer`)),
|
|
8
8
|
});
|
|
9
9
|
|
|
10
|
-
export type OAuthParResponse = v.
|
|
10
|
+
export type OAuthParResponse = v.InferOutput<typeof oauthParResponseSchema>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as v from '
|
|
1
|
+
import * as v from 'valibot';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* OAuth prompt mode values.
|
|
@@ -9,12 +9,6 @@ import * as v from '@badrap/valita';
|
|
|
9
9
|
* - `select_account`: force account selection
|
|
10
10
|
* - `create`: force user registration screen
|
|
11
11
|
*/
|
|
12
|
-
export const oauthPromptSchema = v.
|
|
13
|
-
v.literal('none'),
|
|
14
|
-
v.literal('login'),
|
|
15
|
-
v.literal('consent'),
|
|
16
|
-
v.literal('select_account'),
|
|
17
|
-
v.literal('create'),
|
|
18
|
-
);
|
|
12
|
+
export const oauthPromptSchema = v.picklist(['none', 'login', 'consent', 'select_account', 'create']);
|
|
19
13
|
|
|
20
|
-
export type OAuthPrompt = v.
|
|
14
|
+
export type OAuthPrompt = v.InferOutput<typeof oauthPromptSchema>;
|