@tinyrack/tinyauth-server 0.4.0 → 0.5.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/dist/entities/background-job.entity.d.ts.map +1 -1
- package/dist/entities/background-job.entity.js +15 -3
- package/dist/entities/background-job.entity.js.map +1 -1
- package/dist/entities/oauth-client.entity.d.ts +147 -0
- package/dist/entities/oauth-client.entity.d.ts.map +1 -1
- package/dist/entities/oauth-client.entity.js +10 -0
- package/dist/entities/oauth-client.entity.js.map +1 -1
- package/dist/entities/oauth-code.entity.d.ts +147 -0
- package/dist/entities/oauth-code.entity.d.ts.map +1 -1
- package/dist/entities/oauth-device-code.entity.d.ts +1737 -0
- package/dist/entities/oauth-device-code.entity.d.ts.map +1 -0
- package/dist/entities/oauth-device-code.entity.js +61 -0
- package/dist/entities/oauth-device-code.entity.js.map +1 -0
- package/dist/entities/revoked-token.entity.d.ts +147 -0
- package/dist/entities/revoked-token.entity.d.ts.map +1 -1
- package/dist/entities/scheduler-job.entity.d.ts.map +1 -1
- package/dist/entities/scheduler-job.entity.js +10 -2
- package/dist/entities/scheduler-job.entity.js.map +1 -1
- package/dist/entities/user-consent.entity.d.ts +147 -0
- package/dist/entities/user-consent.entity.d.ts.map +1 -1
- package/dist/entities/user-oauth.entity.d.ts.map +1 -1
- package/dist/entities/user-oauth.entity.js +2 -1
- package/dist/entities/user-oauth.entity.js.map +1 -1
- package/dist/entrypoints/app.d.ts +126 -19
- package/dist/entrypoints/app.d.ts.map +1 -1
- package/dist/entrypoints/app.js +72 -5
- package/dist/entrypoints/app.js.map +1 -1
- package/dist/entrypoints/database/postgres/cli.js +5 -5
- package/dist/entrypoints/database/postgres/cli.js.map +1 -1
- package/dist/entrypoints/database/postgres/compiled-functions.d.ts +146 -94
- package/dist/entrypoints/database/postgres/compiled-functions.d.ts.map +1 -1
- package/dist/entrypoints/database/postgres/compiled-functions.js +881 -122
- package/dist/entrypoints/database/postgres/compiled-functions.js.map +1 -1
- package/dist/entrypoints/database/sqlite/cli.js +2 -2
- package/dist/entrypoints/database/sqlite/cli.js.map +1 -1
- package/dist/entrypoints/database/sqlite/compiled-functions.d.ts +146 -94
- package/dist/entrypoints/database/sqlite/compiled-functions.d.ts.map +1 -1
- package/dist/entrypoints/database/sqlite/compiled-functions.js +881 -122
- package/dist/entrypoints/database/sqlite/compiled-functions.js.map +1 -1
- package/dist/lib/config/client.d.ts +8 -0
- package/dist/lib/config/client.d.ts.map +1 -1
- package/dist/lib/config/client.js +62 -2
- package/dist/lib/config/client.js.map +1 -1
- package/dist/lib/config/resolved.d.ts +4 -0
- package/dist/lib/config/resolved.d.ts.map +1 -1
- package/dist/lib/config/security.d.ts.map +1 -1
- package/dist/lib/config/security.js +25 -2
- package/dist/lib/config/security.js.map +1 -1
- package/dist/lib/crypto.d.ts.map +1 -1
- package/dist/lib/crypto.js +11 -1
- package/dist/lib/crypto.js.map +1 -1
- package/dist/lib/database/entities.d.ts.map +1 -1
- package/dist/lib/database/entities.js +2 -0
- package/dist/lib/database/entities.js.map +1 -1
- package/dist/lib/escape-html.d.ts +7 -0
- package/dist/lib/escape-html.d.ts.map +1 -0
- package/dist/lib/escape-html.js +14 -0
- package/dist/lib/escape-html.js.map +1 -0
- package/dist/migrations/postgres/Migration20260619075007.d.ts +6 -0
- package/dist/migrations/postgres/Migration20260619075007.d.ts.map +1 -0
- package/dist/migrations/postgres/Migration20260619075007.js +86 -0
- package/dist/migrations/postgres/Migration20260619075007.js.map +1 -0
- package/dist/migrations/postgres/Migration20260619191600_unique_oauth_client_client_id.d.ts +6 -0
- package/dist/migrations/postgres/Migration20260619191600_unique_oauth_client_client_id.d.ts.map +1 -0
- package/dist/migrations/postgres/Migration20260619191600_unique_oauth_client_client_id.js +12 -0
- package/dist/migrations/postgres/Migration20260619191600_unique_oauth_client_client_id.js.map +1 -0
- package/dist/migrations/postgres/index.d.ts.map +1 -1
- package/dist/migrations/postgres/index.js +4 -0
- package/dist/migrations/postgres/index.js.map +1 -1
- package/dist/migrations/sqlite/Migration20260619075330.d.ts +6 -0
- package/dist/migrations/sqlite/Migration20260619075330.d.ts.map +1 -0
- package/dist/migrations/sqlite/Migration20260619075330.js +57 -0
- package/dist/migrations/sqlite/Migration20260619075330.js.map +1 -0
- package/dist/migrations/sqlite/Migration20260619191600_unique_oauth_client_client_id.d.ts +6 -0
- package/dist/migrations/sqlite/Migration20260619191600_unique_oauth_client_client_id.d.ts.map +1 -0
- package/dist/migrations/sqlite/Migration20260619191600_unique_oauth_client_client_id.js +12 -0
- package/dist/migrations/sqlite/Migration20260619191600_unique_oauth_client_client_id.js.map +1 -0
- package/dist/migrations/sqlite/index.d.ts.map +1 -1
- package/dist/migrations/sqlite/index.js +4 -0
- package/dist/migrations/sqlite/index.js.map +1 -1
- package/dist/repositories/oauth-device-code.repository.d.ts +20 -0
- package/dist/repositories/oauth-device-code.repository.d.ts.map +1 -0
- package/dist/repositories/oauth-device-code.repository.js +55 -0
- package/dist/repositories/oauth-device-code.repository.js.map +1 -0
- package/dist/routes/.well-known/index.d.ts +29 -3
- package/dist/routes/.well-known/index.d.ts.map +1 -1
- package/dist/routes/.well-known/openid-configuration/get.d.ts +30 -4
- package/dist/routes/.well-known/openid-configuration/get.d.ts.map +1 -1
- package/dist/routes/.well-known/openid-configuration/get.js +5 -2
- package/dist/routes/.well-known/openid-configuration/get.js.map +1 -1
- package/dist/routes/index.d.ts +123 -18
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/oauth/.well-known/openid-configuration/get.d.ts +33 -0
- package/dist/routes/oauth/.well-known/openid-configuration/get.d.ts.map +1 -1
- package/dist/routes/oauth/.well-known/openid-configuration/get.js +78 -44
- package/dist/routes/oauth/.well-known/openid-configuration/get.js.map +1 -1
- package/dist/routes/oauth/authorize/get.d.ts +8 -26
- package/dist/routes/oauth/authorize/get.d.ts.map +1 -1
- package/dist/routes/oauth/authorize/get.js +34 -3
- package/dist/routes/oauth/authorize/get.js.map +1 -1
- package/dist/routes/oauth/cors.d.ts +9 -0
- package/dist/routes/oauth/cors.d.ts.map +1 -0
- package/dist/routes/oauth/cors.js +50 -0
- package/dist/routes/oauth/cors.js.map +1 -0
- package/dist/routes/oauth/device/get-post.d.ts +28 -0
- package/dist/routes/oauth/device/get-post.d.ts.map +1 -0
- package/dist/routes/oauth/device/get-post.js +67 -0
- package/dist/routes/oauth/device/get-post.js.map +1 -0
- package/dist/routes/oauth/device-authorization/post.d.ts +25 -0
- package/dist/routes/oauth/device-authorization/post.d.ts.map +1 -0
- package/dist/routes/oauth/device-authorization/post.js +87 -0
- package/dist/routes/oauth/device-authorization/post.js.map +1 -0
- package/dist/routes/oauth/end-session/get.d.ts +34 -0
- package/dist/routes/oauth/end-session/get.d.ts.map +1 -0
- package/dist/routes/oauth/end-session/get.js +74 -0
- package/dist/routes/oauth/end-session/get.js.map +1 -0
- package/dist/routes/oauth/index.d.ts +95 -16
- package/dist/routes/oauth/index.d.ts.map +1 -1
- package/dist/routes/oauth/index.js +8 -0
- package/dist/routes/oauth/index.js.map +1 -1
- package/dist/routes/oauth/introspect/post.d.ts.map +1 -1
- package/dist/routes/oauth/introspect/post.js +2 -0
- package/dist/routes/oauth/introspect/post.js.map +1 -1
- package/dist/routes/oauth/revoke/post.d.ts.map +1 -1
- package/dist/routes/oauth/revoke/post.js +2 -0
- package/dist/routes/oauth/revoke/post.js.map +1 -1
- package/dist/routes/oauth/token/post.d.ts +2 -0
- package/dist/routes/oauth/token/post.d.ts.map +1 -1
- package/dist/routes/oauth/token/post.js +46 -0
- package/dist/routes/oauth/token/post.js.map +1 -1
- package/dist/routes/oauth/userinfo/get.d.ts +16 -4
- package/dist/routes/oauth/userinfo/get.d.ts.map +1 -1
- package/dist/routes/oauth/userinfo/get.js +50 -30
- package/dist/routes/oauth/userinfo/get.js.map +1 -1
- package/dist/schemas/error.d.ts +100 -0
- package/dist/schemas/error.d.ts.map +1 -1
- package/dist/schemas/error.js +4 -0
- package/dist/schemas/error.js.map +1 -1
- package/dist/schemas/field.d.ts +2 -0
- package/dist/schemas/field.d.ts.map +1 -1
- package/dist/schemas/field.js +6 -1
- package/dist/schemas/field.js.map +1 -1
- package/dist/schemas/response.d.ts +2 -0
- package/dist/schemas/response.d.ts.map +1 -1
- package/dist/schemas/response.js +4 -0
- package/dist/schemas/response.js.map +1 -1
- package/dist/seeders/config.seeder.js +2 -0
- package/dist/seeders/config.seeder.js.map +1 -1
- package/dist/services/container.d.ts +3 -1
- package/dist/services/container.d.ts.map +1 -1
- package/dist/services/jwt.service.d.ts +4 -0
- package/dist/services/jwt.service.d.ts.map +1 -1
- package/dist/services/jwt.service.js +27 -6
- package/dist/services/jwt.service.js.map +1 -1
- package/dist/services/mikro.service.d.ts +2 -0
- package/dist/services/mikro.service.d.ts.map +1 -1
- package/dist/services/mikro.service.js +3 -0
- package/dist/services/mikro.service.js.map +1 -1
- package/dist/services/oauth-authorize.service.d.ts +9 -1
- package/dist/services/oauth-authorize.service.d.ts.map +1 -1
- package/dist/services/oauth-authorize.service.js +109 -17
- package/dist/services/oauth-authorize.service.js.map +1 -1
- package/dist/services/oauth-client.service.d.ts +3 -0
- package/dist/services/oauth-client.service.d.ts.map +1 -1
- package/dist/services/oauth-client.service.js +16 -0
- package/dist/services/oauth-client.service.js.map +1 -1
- package/dist/services/oauth-token.service.d.ts +11 -0
- package/dist/services/oauth-token.service.d.ts.map +1 -1
- package/dist/services/oauth-token.service.js +69 -1
- package/dist/services/oauth-token.service.js.map +1 -1
- package/dist/services/security.service.d.ts +1 -1
- package/dist/services/security.service.d.ts.map +1 -1
- package/dist/services/security.service.js +2 -0
- package/dist/services/security.service.js.map +1 -1
- package/package.json +3 -3
- package/readme.md +5 -1
|
@@ -2,6 +2,75 @@ import { Hono } from 'hono';
|
|
|
2
2
|
import { describeRoute, resolver } from 'hono-openapi';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { TAGS } from '#server/lib/swagger-tags.js';
|
|
5
|
+
export function buildOpenidConfiguration(config) {
|
|
6
|
+
const baseUrl = config.server.public_origin;
|
|
7
|
+
const scopesSupported = new Set([
|
|
8
|
+
'openid',
|
|
9
|
+
'profile',
|
|
10
|
+
'email',
|
|
11
|
+
'offline_access',
|
|
12
|
+
]);
|
|
13
|
+
for (const client of config.clients) {
|
|
14
|
+
for (const scope of client.scope.split(' ')) {
|
|
15
|
+
scopesSupported.add(scope);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
issuer: baseUrl,
|
|
20
|
+
authorization_endpoint: `${baseUrl}/oauth/authorize`,
|
|
21
|
+
token_endpoint: `${baseUrl}/oauth/token`,
|
|
22
|
+
jwks_uri: `${baseUrl}/oauth/.well-known/jwks`,
|
|
23
|
+
response_types_supported: ['code', 'id_token'],
|
|
24
|
+
response_modes_supported: ['query', 'fragment', 'form_post'],
|
|
25
|
+
subject_types_supported: ['public'],
|
|
26
|
+
id_token_signing_alg_values_supported: ['RS256'],
|
|
27
|
+
userinfo_signing_alg_values_supported: ['none'],
|
|
28
|
+
userinfo_endpoint: `${baseUrl}/oauth/userinfo`,
|
|
29
|
+
scopes_supported: [...scopesSupported],
|
|
30
|
+
claims_supported: [
|
|
31
|
+
'sub',
|
|
32
|
+
'iss',
|
|
33
|
+
'aud',
|
|
34
|
+
'exp',
|
|
35
|
+
'iat',
|
|
36
|
+
'nonce',
|
|
37
|
+
'auth_time',
|
|
38
|
+
'at_hash',
|
|
39
|
+
'email',
|
|
40
|
+
'email_verified',
|
|
41
|
+
'name',
|
|
42
|
+
],
|
|
43
|
+
grant_types_supported: [
|
|
44
|
+
'authorization_code',
|
|
45
|
+
'implicit',
|
|
46
|
+
'refresh_token',
|
|
47
|
+
'client_credentials',
|
|
48
|
+
'urn:ietf:params:oauth:grant-type:device_code',
|
|
49
|
+
],
|
|
50
|
+
token_endpoint_auth_methods_supported: [
|
|
51
|
+
'client_secret_basic',
|
|
52
|
+
'client_secret_post',
|
|
53
|
+
'none',
|
|
54
|
+
],
|
|
55
|
+
introspection_endpoint_auth_methods_supported: [
|
|
56
|
+
'client_secret_basic',
|
|
57
|
+
'client_secret_post',
|
|
58
|
+
],
|
|
59
|
+
revocation_endpoint_auth_methods_supported: [
|
|
60
|
+
'client_secret_basic',
|
|
61
|
+
'client_secret_post',
|
|
62
|
+
],
|
|
63
|
+
code_challenge_methods_supported: ['S256'],
|
|
64
|
+
introspection_endpoint: `${baseUrl}/oauth/introspect`,
|
|
65
|
+
revocation_endpoint: `${baseUrl}/oauth/revoke`,
|
|
66
|
+
end_session_endpoint: `${baseUrl}/oauth/end_session`,
|
|
67
|
+
device_authorization_endpoint: `${baseUrl}/oauth/device_authorization`,
|
|
68
|
+
ui_locales_supported: config.i18n.supported_languages,
|
|
69
|
+
request_parameter_supported: false,
|
|
70
|
+
request_uri_parameter_supported: false,
|
|
71
|
+
claims_parameter_supported: false,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
5
74
|
export const oidcConfigGet = new Hono().get('/.well-known/openid-configuration', describeRoute({
|
|
6
75
|
tags: [TAGS.OPENID],
|
|
7
76
|
summary: 'OpenID Provider Configuration',
|
|
@@ -56,6 +125,14 @@ export const oidcConfigGet = new Hono().get('/.well-known/openid-configuration',
|
|
|
56
125
|
.array(z.string())
|
|
57
126
|
.optional()
|
|
58
127
|
.describe('JSON array containing a list of Client Authentication methods'),
|
|
128
|
+
introspection_endpoint_auth_methods_supported: z
|
|
129
|
+
.array(z.string())
|
|
130
|
+
.optional()
|
|
131
|
+
.describe('JSON array containing a list of Token Introspection Client Authentication methods'),
|
|
132
|
+
revocation_endpoint_auth_methods_supported: z
|
|
133
|
+
.array(z.string())
|
|
134
|
+
.optional()
|
|
135
|
+
.describe('JSON array containing a list of Token Revocation Client Authentication methods'),
|
|
59
136
|
code_challenge_methods_supported: z
|
|
60
137
|
.array(z.string())
|
|
61
138
|
.optional()
|
|
@@ -96,51 +173,8 @@ export const oidcConfigGet = new Hono().get('/.well-known/openid-configuration',
|
|
|
96
173
|
},
|
|
97
174
|
}), async (c) => {
|
|
98
175
|
const { config } = c.var.services;
|
|
99
|
-
const baseUrl = config.server.public_origin;
|
|
100
|
-
const configuration = {
|
|
101
|
-
issuer: baseUrl,
|
|
102
|
-
authorization_endpoint: `${baseUrl}/oauth/authorize`,
|
|
103
|
-
token_endpoint: `${baseUrl}/oauth/token`,
|
|
104
|
-
jwks_uri: `${baseUrl}/oauth/.well-known/jwks`,
|
|
105
|
-
response_types_supported: ['code', 'id_token'],
|
|
106
|
-
response_modes_supported: ['query', 'fragment'],
|
|
107
|
-
subject_types_supported: ['public'],
|
|
108
|
-
id_token_signing_alg_values_supported: ['RS256'],
|
|
109
|
-
userinfo_endpoint: `${baseUrl}/oauth/userinfo`,
|
|
110
|
-
scopes_supported: ['openid', 'profile', 'email', 'offline_access'],
|
|
111
|
-
claims_supported: [
|
|
112
|
-
'sub',
|
|
113
|
-
'iss',
|
|
114
|
-
'aud',
|
|
115
|
-
'exp',
|
|
116
|
-
'iat',
|
|
117
|
-
'nonce',
|
|
118
|
-
'auth_time',
|
|
119
|
-
'at_hash',
|
|
120
|
-
'email',
|
|
121
|
-
'email_verified',
|
|
122
|
-
'name',
|
|
123
|
-
],
|
|
124
|
-
grant_types_supported: [
|
|
125
|
-
'authorization_code',
|
|
126
|
-
'implicit',
|
|
127
|
-
'refresh_token',
|
|
128
|
-
],
|
|
129
|
-
token_endpoint_auth_methods_supported: [
|
|
130
|
-
'client_secret_basic',
|
|
131
|
-
'client_secret_post',
|
|
132
|
-
'none',
|
|
133
|
-
],
|
|
134
|
-
code_challenge_methods_supported: ['S256'],
|
|
135
|
-
introspection_endpoint: `${baseUrl}/oauth/introspect`,
|
|
136
|
-
revocation_endpoint: `${baseUrl}/oauth/revoke`,
|
|
137
|
-
ui_locales_supported: config.i18n.supported_languages,
|
|
138
|
-
request_parameter_supported: false,
|
|
139
|
-
request_uri_parameter_supported: false,
|
|
140
|
-
claims_parameter_supported: false,
|
|
141
|
-
};
|
|
142
176
|
// Set Cache-Control header
|
|
143
177
|
c.header('Cache-Control', 'public, max-age=3600');
|
|
144
|
-
return c.json(
|
|
178
|
+
return c.json(buildOpenidConfiguration(config), 200);
|
|
145
179
|
});
|
|
146
180
|
//# sourceMappingURL=get.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get.js","sourceRoot":"","sources":["../../../../../src/routes/oauth/.well-known/openid-configuration/get.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"get.js","sourceRoot":"","sources":["../../../../../src/routes/oauth/.well-known/openid-configuration/get.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,34 +16,16 @@ export declare const authorizeGet: import("hono/hono-base").HonoBase<AppEnv, {
|
|
|
16
16
|
max_age?: string | string[];
|
|
17
17
|
reauthenticated?: string | string[];
|
|
18
18
|
display?: string | string[];
|
|
19
|
+
response_mode?: string | string[];
|
|
20
|
+
login_hint?: string | string[];
|
|
21
|
+
ui_locales?: string | string[];
|
|
22
|
+
id_token_hint?: string | string[];
|
|
23
|
+
acr_values?: string | string[];
|
|
19
24
|
};
|
|
20
25
|
};
|
|
21
|
-
output:
|
|
22
|
-
outputFormat:
|
|
23
|
-
status:
|
|
24
|
-
} | {
|
|
25
|
-
input: {
|
|
26
|
-
query: {
|
|
27
|
-
response_type: string | string[];
|
|
28
|
-
redirect_uri: string | string[];
|
|
29
|
-
client_id: string | string[];
|
|
30
|
-
state?: string | string[];
|
|
31
|
-
code_challenge?: string | string[];
|
|
32
|
-
code_challenge_method?: string | string[];
|
|
33
|
-
scope?: string | string[];
|
|
34
|
-
nonce?: string | string[];
|
|
35
|
-
prompt?: string | string[];
|
|
36
|
-
max_age?: string | string[];
|
|
37
|
-
reauthenticated?: string | string[];
|
|
38
|
-
display?: string | string[];
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
|
-
output: {
|
|
42
|
-
error: string;
|
|
43
|
-
error_description: string;
|
|
44
|
-
};
|
|
45
|
-
outputFormat: "json";
|
|
46
|
-
status: 400;
|
|
26
|
+
output: {};
|
|
27
|
+
outputFormat: string;
|
|
28
|
+
status: import("hono/utils/http-status").StatusCode;
|
|
47
29
|
};
|
|
48
30
|
};
|
|
49
31
|
}, "/", "/authorize">;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get.d.ts","sourceRoot":"","sources":["../../../../src/routes/oauth/authorize/get.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"get.d.ts","sourceRoot":"","sources":["../../../../src/routes/oauth/authorize/get.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAUtD,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAuMxB,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
2
|
import { describeRoute, resolver, validator } from 'hono-openapi';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
+
import { escapeHtml } from '../../../lib/escape-html.js';
|
|
4
5
|
import { OPENAPI_SECURITY } from "../../../lib/openapi.js";
|
|
5
6
|
import { TAGS } from "../../../lib/swagger-tags.js";
|
|
6
7
|
import { verifyAuth } from "../../../middleware/auth.js";
|
|
@@ -38,6 +39,11 @@ export const authorizeGet = new Hono().get('/authorize', describeRoute({
|
|
|
38
39
|
max_age: f.maxAge.optional(),
|
|
39
40
|
reauthenticated: z.literal('1').optional(),
|
|
40
41
|
display: f.display.optional(),
|
|
42
|
+
response_mode: z.enum(['query', 'fragment', 'form_post']).optional(),
|
|
43
|
+
login_hint: z.string().min(1).max(1000).optional(),
|
|
44
|
+
ui_locales: z.string().min(1).max(1000).optional(),
|
|
45
|
+
id_token_hint: z.string().min(1).max(4000).optional(),
|
|
46
|
+
acr_values: z.string().min(1).max(1000).optional(),
|
|
41
47
|
})), verifyAuth({ optional: true }), async (c) => {
|
|
42
48
|
const query = c.req.valid('query');
|
|
43
49
|
const { oauthAuthorizeService } = c.var.services;
|
|
@@ -49,8 +55,19 @@ export const authorizeGet = new Hono().get('/authorize', describeRoute({
|
|
|
49
55
|
error_description: errorDescription,
|
|
50
56
|
}, 400);
|
|
51
57
|
}
|
|
58
|
+
if (query.response_mode === 'form_post') {
|
|
59
|
+
const params = {
|
|
60
|
+
error,
|
|
61
|
+
error_description: errorDescription,
|
|
62
|
+
};
|
|
63
|
+
if (query.state) {
|
|
64
|
+
params['state'] = query.state;
|
|
65
|
+
}
|
|
66
|
+
return c.html(buildFormPostResponse(redirectUri, params));
|
|
67
|
+
}
|
|
52
68
|
const url = new URL(redirectUri);
|
|
53
|
-
const useFragment = query.
|
|
69
|
+
const useFragment = query.response_mode === 'fragment' ||
|
|
70
|
+
(query.response_type === 'id_token' && query.response_mode !== 'query');
|
|
54
71
|
const params = useFragment ? new URLSearchParams() : url.searchParams;
|
|
55
72
|
params.set('error', error);
|
|
56
73
|
params.set('error_description', errorDescription);
|
|
@@ -75,6 +92,9 @@ export const authorizeGet = new Hono().get('/authorize', describeRoute({
|
|
|
75
92
|
};
|
|
76
93
|
}
|
|
77
94
|
const result = await oauthAuthorizeService.authorize(authorizeParams);
|
|
95
|
+
if (result.type === 'form_post') {
|
|
96
|
+
return c.html(buildFormPostResponse(result.url, result.params ?? {}));
|
|
97
|
+
}
|
|
78
98
|
// Redirect based on result
|
|
79
99
|
return c.redirect(result.url);
|
|
80
100
|
}
|
|
@@ -106,9 +126,20 @@ export const authorizeGet = new Hono().get('/authorize', describeRoute({
|
|
|
106
126
|
if (error instanceof e.InvalidPrompt.Error) {
|
|
107
127
|
return redirectWithError('invalid_request', error.message, query.redirect_uri);
|
|
108
128
|
}
|
|
109
|
-
// Log unexpected errors
|
|
129
|
+
// Log unexpected errors. Do not redirect unexpected failures to the
|
|
130
|
+
// client-supplied redirect_uri because this handler cannot prove that
|
|
131
|
+
// redirect_uri validation completed successfully.
|
|
110
132
|
c.var.logger.error({ err: error }, 'Unexpected authorize error');
|
|
111
|
-
return
|
|
133
|
+
return c.json({
|
|
134
|
+
error: 'server_error',
|
|
135
|
+
error_description: 'An unexpected error occurred',
|
|
136
|
+
}, 500);
|
|
112
137
|
}
|
|
113
138
|
});
|
|
139
|
+
function buildFormPostResponse(action, params) {
|
|
140
|
+
const inputs = Object.entries(params)
|
|
141
|
+
.map(([name, value]) => `<input type="hidden" name="${escapeHtml(name)}" value="${escapeHtml(value)}">`)
|
|
142
|
+
.join('');
|
|
143
|
+
return `<!doctype html><html><head><title>Submit Authorization Response</title></head><body><form method="post" action="${escapeHtml(action)}">${inputs}<noscript><button type="submit">Continue</button></noscript></form><script>document.forms[0].submit();</script></body></html>`;
|
|
144
|
+
}
|
|
114
145
|
//# sourceMappingURL=get.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get.js","sourceRoot":"","sources":["../../../../src/routes/oauth/authorize/get.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,CAAC,EAAE,MAAM,2BAA2B,CAAC;AAC9C,OAAO,EAAE,CAAC,EAAE,MAAM,2BAA2B,CAAC;AAC9C,OAAO,EAAE,CAAC,EAAE,MAAM,8BAA8B,CAAC;AAGjD,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,IAAI,EAAU,CAAC,GAAG,CAChD,YAAY,EACZ,aAAa,CAAC;IACZ,IAAI,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC;IACnB,QAAQ,EAAE,gBAAgB,CAAC,qBAAqB;IAChD,OAAO,EAAE,WAAW;IACpB,WAAW,EAAE,+BAA+B;IAC5C,SAAS,EAAE;QACT,GAAG,EAAE;YACH,WAAW,EAAE,UAAU;SACxB;QACD,GAAG,EAAE;YACH,OAAO,EAAE;gBACP,kBAAkB,EAAE;oBAClB,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC;iBAC/B;aACF;YACD,WAAW,EAAE,aAAa;SAC3B;KACF;CACF,CAAC,EACF,SAAS,CACP,OAAO,EACP,CAAC,CAAC,MAAM,CAAC;IACP,aAAa,EAAE,CAAC,CAAC,YAAY;IAC7B,YAAY,EAAE,CAAC,CAAC,WAAW;IAC3B,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE;IACzB,SAAS,EAAE,CAAC,CAAC,QAAQ;IACrB,cAAc,EAAE,CAAC,CAAC,aAAa,CAAC,QAAQ,EAAE;IAC1C,qBAAqB,EAAE,CAAC,CAAC,mBAAmB,CAAC,QAAQ,EAAE;IACvD,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE;IACzB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE;IACzB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;IAC3B,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;IAC5B,eAAe,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAC1C,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE;
|
|
1
|
+
{"version":3,"file":"get.js","sourceRoot":"","sources":["../../../../src/routes/oauth/authorize/get.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Context, Next } from 'hono';
|
|
2
|
+
import type { AppEnv } from '../../lib/app-env.js';
|
|
3
|
+
type OAuthCorsClient = {
|
|
4
|
+
webOrigins: string[];
|
|
5
|
+
};
|
|
6
|
+
export declare function oauthCorsMiddleware(c: Context<AppEnv>, next: Next): Promise<Response | undefined>;
|
|
7
|
+
export declare function setOAuthClientCorsHeaders(c: Context<AppEnv>, client: OAuthCorsClient): void;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=cors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../../src/routes/oauth/cors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,KAAK,eAAe,GAAG;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,CAAC;AASF,wBAAsB,mBAAmB,CACvC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,EAClB,IAAI,EAAE,IAAI,GACT,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAa/B;AAED,wBAAgB,yBAAyB,CACvC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,EAClB,MAAM,EAAE,eAAe,GACtB,IAAI,CAeN"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const PUBLIC_METADATA_PATHS = [
|
|
2
|
+
'/oauth/.well-known/openid-configuration',
|
|
3
|
+
'/oauth/.well-known/jwks',
|
|
4
|
+
];
|
|
5
|
+
const PREFLIGHT_PATHS = ['/oauth/token', '/oauth/revoke'];
|
|
6
|
+
export async function oauthCorsMiddleware(c, next) {
|
|
7
|
+
if (c.req.method === 'OPTIONS') {
|
|
8
|
+
return handleOAuthPreflight(c);
|
|
9
|
+
}
|
|
10
|
+
await next();
|
|
11
|
+
if (isPublicMetadataPath(c.req.path) && c.req.header('origin')) {
|
|
12
|
+
c.res.headers.delete('Access-Control-Allow-Credentials');
|
|
13
|
+
c.header('Access-Control-Allow-Origin', '*');
|
|
14
|
+
}
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
export function setOAuthClientCorsHeaders(c, client) {
|
|
18
|
+
const origin = c.req.header('origin');
|
|
19
|
+
c.res.headers.delete('Access-Control-Allow-Origin');
|
|
20
|
+
c.res.headers.delete('Access-Control-Allow-Credentials');
|
|
21
|
+
if (!origin) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
c.header('Vary', 'Origin', { append: true });
|
|
25
|
+
if (!client.webOrigins.includes(origin)) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
c.header('Access-Control-Allow-Origin', origin);
|
|
29
|
+
}
|
|
30
|
+
async function handleOAuthPreflight(c) {
|
|
31
|
+
const origin = c.req.header('origin');
|
|
32
|
+
if (origin && PREFLIGHT_PATHS.includes(c.req.path)) {
|
|
33
|
+
const { oauthClientService } = c.var.services;
|
|
34
|
+
if (await oauthClientService.isAllowedWebOrigin(origin)) {
|
|
35
|
+
c.header('Access-Control-Allow-Origin', origin);
|
|
36
|
+
c.header('Vary', 'Origin');
|
|
37
|
+
c.header('Access-Control-Allow-Methods', 'POST');
|
|
38
|
+
const requestHeaders = c.req.header('access-control-request-headers');
|
|
39
|
+
if (requestHeaders) {
|
|
40
|
+
c.header('Access-Control-Allow-Headers', requestHeaders);
|
|
41
|
+
c.header('Vary', 'Access-Control-Request-Headers', { append: true });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return c.body(null, 204);
|
|
46
|
+
}
|
|
47
|
+
function isPublicMetadataPath(path) {
|
|
48
|
+
return PUBLIC_METADATA_PATHS.includes(path);
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=cors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.js","sourceRoot":"","sources":["../../../src/routes/oauth/cors.ts"],"names":[],"mappings":"AAOA,MAAM,qBAAqB,GAAG;IAC5B,yCAAyC;IACzC,yBAAyB;CAC1B,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;AAE1D,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,CAAkB,EAClB,IAAU;IAEV,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,oBAAoB,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC;IAED,MAAM,IAAI,EAAE,CAAC;IAEb,IAAI,oBAAoB,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/D,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,kCAAkC,CAAC,CAAC;QACzD,CAAC,CAAC,MAAM,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,CAAkB,EAClB,MAAuB;IAEvB,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,6BAA6B,CAAC,CAAC;IACpD,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,kCAAkC,CAAC,CAAC;IAEzD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;IACT,CAAC;IAED,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACxC,OAAO;IACT,CAAC;IAED,CAAC,CAAC,MAAM,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,CAAkB;IACpD,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtC,IAAI,MAAM,IAAI,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,MAAM,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC9C,IAAI,MAAM,kBAAkB,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;YACxD,CAAC,CAAC,MAAM,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;YAChD,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAC3B,CAAC,CAAC,MAAM,CAAC,8BAA8B,EAAE,MAAM,CAAC,CAAC;YACjD,MAAM,cAAc,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,gCAAgC,CAAC,CAAC;YACtE,IAAI,cAAc,EAAE,CAAC;gBACnB,CAAC,CAAC,MAAM,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAC;gBACzD,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,gCAAgC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YACvE,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,oBAAoB,CAAC,IAAY;IACxC,OAAO,qBAAqB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AppEnv } from '../../../lib/app-env.ts';
|
|
2
|
+
export declare const deviceGetPost: import("hono/hono-base").HonoBase<AppEnv, {
|
|
3
|
+
"/device": {
|
|
4
|
+
$get: {
|
|
5
|
+
input: {};
|
|
6
|
+
output: {};
|
|
7
|
+
outputFormat: string;
|
|
8
|
+
status: import("hono/utils/http-status").StatusCode;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
} & {
|
|
12
|
+
"/device": {
|
|
13
|
+
$post: {
|
|
14
|
+
input: {
|
|
15
|
+
form: {
|
|
16
|
+
user_code: string;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
output: {
|
|
20
|
+
status: string;
|
|
21
|
+
client_id: string;
|
|
22
|
+
};
|
|
23
|
+
outputFormat: "json";
|
|
24
|
+
status: import("hono/utils/http-status").ContentfulStatusCode;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
}, "/", "/device">;
|
|
28
|
+
//# sourceMappingURL=get-post.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-post.d.ts","sourceRoot":"","sources":["../../../../src/routes/oauth/device/get-post.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAUtD,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;kBAmFvB,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { describeRoute, validator } from 'hono-openapi';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { escapeHtml } from '../../../lib/escape-html.js';
|
|
5
|
+
import { TAGS } from "../../../lib/swagger-tags.js";
|
|
6
|
+
import { verifyAuth } from "../../../middleware/auth.js";
|
|
7
|
+
import { e } from "../../../schemas/error.js";
|
|
8
|
+
const DeviceVerificationRequestBody = z.object({
|
|
9
|
+
user_code: z.string().min(1).max(64),
|
|
10
|
+
});
|
|
11
|
+
export const deviceGetPost = new Hono()
|
|
12
|
+
.get('/device', describeRoute({
|
|
13
|
+
tags: [TAGS.OPENID],
|
|
14
|
+
summary: 'Device Verification',
|
|
15
|
+
description: 'User-facing OAuth device verification page',
|
|
16
|
+
responses: {
|
|
17
|
+
200: { description: 'Device verification form' },
|
|
18
|
+
},
|
|
19
|
+
}), verifyAuth({ optional: true }), async (c) => {
|
|
20
|
+
const userCode = c.req.query('user_code') ?? '';
|
|
21
|
+
const verifiedUser = c.var.verifiedUser;
|
|
22
|
+
if (!verifiedUser) {
|
|
23
|
+
const loginUrl = `/login?return_to=${encodeURIComponent(`/oauth/device?user_code=${encodeURIComponent(userCode)}`)}`;
|
|
24
|
+
return c.html(`<!doctype html><html><body><p>Sign in to approve the device.</p><p><a href="${escapeHtml(loginUrl)}">Sign in</a></p></body></html>`);
|
|
25
|
+
}
|
|
26
|
+
const { mikro, securityService } = c.var.services;
|
|
27
|
+
let deviceDetails = '';
|
|
28
|
+
if (userCode) {
|
|
29
|
+
const userCodeHash = await securityService.hashOpaqueToken('oauth-device-user-code', userCode.toUpperCase());
|
|
30
|
+
const deviceCode = await mikro.oauthDeviceCode.findPendingByUserCodeHash(userCodeHash);
|
|
31
|
+
if (deviceCode) {
|
|
32
|
+
await mikro.em.populate(deviceCode, ['client']);
|
|
33
|
+
const scopes = deviceCode.scope
|
|
34
|
+
.map((scope) => `<li>${escapeHtml(scope)}</li>`)
|
|
35
|
+
.join('');
|
|
36
|
+
deviceDetails = `<section><h2>${escapeHtml(deviceCode.client.name)}</h2><p>Requested scopes:</p><ul>${scopes}</ul></section>`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return c.html(`<!doctype html><html><body>${deviceDetails}<form method="post"><input name="user_code" value="${escapeHtml(userCode)}"><button type="submit">Approve</button></form></body></html>`);
|
|
40
|
+
})
|
|
41
|
+
.post('/device', describeRoute({
|
|
42
|
+
tags: [TAGS.OPENID],
|
|
43
|
+
summary: 'Approve Device Authorization',
|
|
44
|
+
description: 'Approves a pending OAuth device authorization request',
|
|
45
|
+
responses: {
|
|
46
|
+
200: { description: 'Device authorization approved' },
|
|
47
|
+
400: { description: 'Invalid device user code' },
|
|
48
|
+
},
|
|
49
|
+
}), validator('form', DeviceVerificationRequestBody), verifyAuth(), async (c) => {
|
|
50
|
+
const { user_code: userCode } = c.req.valid('form');
|
|
51
|
+
const { mikro, securityService } = c.var.services;
|
|
52
|
+
const userCodeHash = await securityService.hashOpaqueToken('oauth-device-user-code', userCode.toUpperCase());
|
|
53
|
+
const user = c.var.verifiedUser.user;
|
|
54
|
+
const deviceCode = await mikro.oauthDeviceCode.approvePendingByUserCodeHash({
|
|
55
|
+
userCodeHash,
|
|
56
|
+
userSub: user.sub,
|
|
57
|
+
approvedAt: new Date(),
|
|
58
|
+
});
|
|
59
|
+
if (!deviceCode) {
|
|
60
|
+
throw new e.InvalidDeviceCode.Error();
|
|
61
|
+
}
|
|
62
|
+
return c.json({
|
|
63
|
+
status: 'approved',
|
|
64
|
+
client_id: deviceCode.client.clientId,
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=get-post.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-post.js","sourceRoot":"","sources":["../../../../src/routes/oauth/device/get-post.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { AppEnv } from '../../../lib/app-env.js';
|
|
2
|
+
export declare const deviceAuthorizationPost: import("hono/hono-base").HonoBase<AppEnv, {
|
|
3
|
+
"/device_authorization": {
|
|
4
|
+
$post: {
|
|
5
|
+
input: {
|
|
6
|
+
form: {
|
|
7
|
+
client_id?: import("hono/types").ParsedFormValue | import("hono/types").ParsedFormValue[];
|
|
8
|
+
client_secret?: import("hono/types").ParsedFormValue | import("hono/types").ParsedFormValue[];
|
|
9
|
+
scope?: import("hono/types").ParsedFormValue | import("hono/types").ParsedFormValue[];
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
output: {
|
|
13
|
+
device_code: string;
|
|
14
|
+
user_code: string;
|
|
15
|
+
verification_uri: string;
|
|
16
|
+
verification_uri_complete: string;
|
|
17
|
+
expires_in: number;
|
|
18
|
+
interval: number;
|
|
19
|
+
};
|
|
20
|
+
outputFormat: "json";
|
|
21
|
+
status: 200;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
}, "/", "/device_authorization">;
|
|
25
|
+
//# sourceMappingURL=post.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post.d.ts","sourceRoot":"","sources":["../../../../src/routes/oauth/device-authorization/post.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AA0BtD,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;gCA2FnC,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { describeRoute, validator } from 'hono-openapi';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { getRandomBytes, toBase64Url } from '../../../lib/base64url.js';
|
|
5
|
+
import { TAGS } from '../../../lib/swagger-tags.js';
|
|
6
|
+
import { f } from '../../../schemas/field.js';
|
|
7
|
+
import { parseBasicClientCredentials, setBasicClientAuthChallengeIfInvalidClientCredentials, throwInvalidClientCredentialsWithBasicChallenge, } from '../client-auth.js';
|
|
8
|
+
const DEVICE_CODE_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:device_code';
|
|
9
|
+
const DEVICE_CODE_EXPIRES_IN = 600;
|
|
10
|
+
const DEVICE_CODE_INTERVAL = 5;
|
|
11
|
+
const DeviceAuthorizationRequestBody = z
|
|
12
|
+
.object({
|
|
13
|
+
client_id: f.clientId.optional(),
|
|
14
|
+
client_secret: f.clientSecret.optional(),
|
|
15
|
+
scope: f.scope.optional(),
|
|
16
|
+
})
|
|
17
|
+
.describe('OAuth2 device authorization request payload');
|
|
18
|
+
function createUserCode() {
|
|
19
|
+
return toBase64Url(getRandomBytes(8)).toUpperCase();
|
|
20
|
+
}
|
|
21
|
+
export const deviceAuthorizationPost = new Hono().post('/device_authorization', describeRoute({
|
|
22
|
+
tags: [TAGS.OPENID],
|
|
23
|
+
summary: 'Device Authorization',
|
|
24
|
+
description: 'OAuth 2.0 Device Authorization endpoint',
|
|
25
|
+
responses: {
|
|
26
|
+
200: { description: 'Device authorization response' },
|
|
27
|
+
401: { description: 'Invalid client credentials' },
|
|
28
|
+
},
|
|
29
|
+
}), validator('form', DeviceAuthorizationRequestBody), async (c) => {
|
|
30
|
+
const body = c.req.valid('form');
|
|
31
|
+
const { config, oauthClientService, securityService, mikro } = c.var.services;
|
|
32
|
+
const authorizationHeader = c.req.header('authorization');
|
|
33
|
+
const basicCredentials = parseBasicClientCredentials(authorizationHeader);
|
|
34
|
+
if (basicCredentials === null) {
|
|
35
|
+
throwInvalidClientCredentialsWithBasicChallenge(c);
|
|
36
|
+
}
|
|
37
|
+
if (basicCredentials && body.client_secret) {
|
|
38
|
+
throwInvalidClientCredentialsWithBasicChallenge(c);
|
|
39
|
+
}
|
|
40
|
+
if (basicCredentials && body.client_id) {
|
|
41
|
+
if (basicCredentials.clientId !== body.client_id) {
|
|
42
|
+
throwInvalidClientCredentialsWithBasicChallenge(c);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const clientId = basicCredentials?.clientId ?? body.client_id;
|
|
46
|
+
if (!clientId) {
|
|
47
|
+
throwInvalidClientCredentialsWithBasicChallenge(c);
|
|
48
|
+
}
|
|
49
|
+
const client = await oauthClientService.findByClientId(clientId);
|
|
50
|
+
oauthClientService.validateEnabled(client);
|
|
51
|
+
oauthClientService.validateGrantType(client, DEVICE_CODE_GRANT_TYPE);
|
|
52
|
+
const clientSecret = basicCredentials?.clientSecret ?? body.client_secret;
|
|
53
|
+
try {
|
|
54
|
+
await oauthClientService.validateClientSecretIfRequired(clientId, clientSecret);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
if (authorizationHeader) {
|
|
58
|
+
setBasicClientAuthChallengeIfInvalidClientCredentials(c, err);
|
|
59
|
+
}
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
const requestedScopes = body.scope ? body.scope.split(' ') : [];
|
|
63
|
+
oauthClientService.validateScopes(client, requestedScopes);
|
|
64
|
+
const deviceCode = toBase64Url(getRandomBytes(32));
|
|
65
|
+
const userCode = createUserCode();
|
|
66
|
+
const deviceCodeHash = await securityService.hashOpaqueToken('oauth-device-code', deviceCode);
|
|
67
|
+
const userCodeHash = await securityService.hashOpaqueToken('oauth-device-user-code', userCode);
|
|
68
|
+
await mikro.oauthDeviceCode.createDeviceAuthorization({
|
|
69
|
+
clientId: client.id,
|
|
70
|
+
deviceCodeHash,
|
|
71
|
+
userCodeHash,
|
|
72
|
+
scope: requestedScopes,
|
|
73
|
+
expiresInSeconds: DEVICE_CODE_EXPIRES_IN,
|
|
74
|
+
});
|
|
75
|
+
const verificationUri = `${config.server.public_origin}/oauth/device`;
|
|
76
|
+
const verificationUriComplete = new URL(verificationUri);
|
|
77
|
+
verificationUriComplete.searchParams.set('user_code', userCode);
|
|
78
|
+
return c.json({
|
|
79
|
+
device_code: deviceCode,
|
|
80
|
+
user_code: userCode,
|
|
81
|
+
verification_uri: verificationUri,
|
|
82
|
+
verification_uri_complete: verificationUriComplete.toString(),
|
|
83
|
+
expires_in: DEVICE_CODE_EXPIRES_IN,
|
|
84
|
+
interval: DEVICE_CODE_INTERVAL,
|
|
85
|
+
}, 200);
|
|
86
|
+
});
|
|
87
|
+
//# sourceMappingURL=post.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post.js","sourceRoot":"","sources":["../../../../src/routes/oauth/device-authorization/post.ts"],"names":[],"mappings":"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"}
|