@julr/sesame 0.5.1 → 0.6.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/LICENSE.md +1 -1
- package/README.md +405 -62
- package/build/authorize_controller-BiycO4be.js +251 -0
- package/build/chunk-DF48asd8.js +9 -0
- package/build/{client_info_controller-BucHGx4u.js → client_info_controller-AcOG8lWu.js} +11 -3
- package/build/commands/sesame_client.d.ts +20 -0
- package/build/commands/sesame_key.d.ts +12 -0
- package/build/commands/sesame_purge.d.ts +0 -2
- package/build/commands/sesame_purge.js +15 -3
- package/build/configure-DkDkIlt8.js +27 -0
- package/build/configure.js +2 -24
- package/build/consent_controller-Dsdhv6-f.js +108 -0
- package/build/id_token_service-CpTzOUDe.js +54 -0
- package/build/index.d.ts +1 -1
- package/build/index.js +30 -10
- package/build/{introspect_controller-6bRt9sZt.js → introspect_controller-DvOp9scr.js} +21 -7
- package/build/issue_authorization_code-B9ERu1uO.js +40 -0
- package/build/jwks_controller-keo4kBZc.js +26 -0
- package/build/{main-EbeMS5S9.js → main-DGBJhq3E.js} +34 -4
- package/build/{metadata_controller-DeaMRnUr.js → metadata_controller-BVsTo0Gp.js} +83 -6
- package/build/{oauth_access_token-bsoM5KeU.js → oauth_access_token-Cz_5gNBx.js} +12 -1
- package/build/oauth_client-BSanvSql.js +63 -0
- package/build/oauth_error-C7UhDb2q.js +189 -0
- package/build/providers/sesame_provider.js +14 -3
- package/build/{register_controller-sIJ1rxdM.js → register_controller-gbq7p8a5.js} +46 -7
- package/build/{revoke_controller-D6isoQCi.js → revoke_controller-z_ghrEB7.js} +21 -8
- package/build/services/main.js +7 -3
- package/build/sesame_manager-B1Jgq1v2.js +6 -0
- package/build/sesame_manager-DYUSZ0NC.js +693 -0
- package/build/src/actions/authorize.d.ts +46 -0
- package/build/src/actions/exchange_authorization_code.d.ts +34 -0
- package/build/src/actions/exchange_client_credentials.d.ts +28 -0
- package/build/src/actions/exchange_refresh_token.d.ts +59 -0
- package/build/src/actions/issue_authorization_code.d.ts +26 -0
- package/build/src/controllers/authorize_controller.d.ts +13 -12
- package/build/src/controllers/consent_controller.d.ts +5 -0
- package/build/src/controllers/jwks_controller.d.ts +14 -0
- package/build/src/controllers/metadata_controller.d.ts +8 -1
- package/build/src/controllers/token_controller.d.ts +8 -5
- package/build/src/controllers/userinfo_controller.d.ts +14 -0
- package/build/src/guard/main.js +5 -5
- package/build/src/middleware/any_scope_middleware.js +11 -1
- package/build/src/middleware/scope_middleware.js +11 -1
- package/build/src/models/oauth_authorization_code.d.ts +1 -0
- package/build/src/models/oauth_pending_authorization_request.d.ts +1 -0
- package/build/src/oauth_error.d.ts +1 -1
- package/build/src/routes.d.ts +3 -1
- package/build/src/services/id_token_service.d.ts +30 -0
- package/build/src/services/key_service.d.ts +20 -0
- package/build/src/sesame_manager.d.ts +54 -3
- package/build/src/types.d.ts +112 -0
- package/build/stubs/main.ts +5 -0
- package/build/stubs/migrations/create_oauth_authorization_codes_table.stub +1 -0
- package/build/stubs/migrations/create_oauth_pending_authorization_requests_table.stub +1 -0
- package/build/stubs/migrations/create_oauth_refresh_tokens_table.stub +1 -1
- package/build/token_controller-DyI7oy-U.js +481 -0
- package/build/token_service-DwnfAR9F.js +59 -0
- package/build/userinfo_controller-RLk8cN_o.js +40 -0
- package/build/vite.config.d.ts +2 -0
- package/package.json +26 -41
- package/build/authorize_controller-YUfAy-R2.js +0 -138
- package/build/client_service-WTNMqWzY.js +0 -65
- package/build/consent_controller-Dprwd1ed.js +0 -85
- package/build/decorate-BKZEjPRg.js +0 -15
- package/build/oauth_client-BIoY5jBR.js +0 -24
- package/build/oauth_error-CnJ3L8tf.js +0 -94
- package/build/sesame_manager-Bu4MHqZV.js +0 -4
- package/build/sesame_manager-DwDZy5Vy.js +0 -167
- package/build/src/grants/authorization_code_grant.d.ts +0 -23
- package/build/src/grants/client_credentials_grant.d.ts +0 -23
- package/build/src/grants/refresh_token_grant.d.ts +0 -27
- package/build/token_controller-DzcrLMyS.js +0 -194
- package/build/token_service-fhoA4slP.js +0 -31
|
@@ -1,11 +1,24 @@
|
|
|
1
|
-
import
|
|
2
|
-
import "./
|
|
3
|
-
import
|
|
4
|
-
import "./oauth_error-
|
|
5
|
-
import "./
|
|
6
|
-
import { t as TokenService } from "./token_service-
|
|
7
|
-
|
|
1
|
+
import "./chunk-DF48asd8.js";
|
|
2
|
+
import { a as OAuthRefreshToken, o as ClientService, t as SesameManager } from "./sesame_manager-DYUSZ0NC.js";
|
|
3
|
+
import "./oauth_client-BSanvSql.js";
|
|
4
|
+
import "./oauth_error-C7UhDb2q.js";
|
|
5
|
+
import { t as OAuthAccessToken } from "./oauth_access_token-Cz_5gNBx.js";
|
|
6
|
+
import { t as TokenService } from "./token_service-DwnfAR9F.js";
|
|
7
|
+
//#region src/controllers/introspect_controller.ts
|
|
8
8
|
const INACTIVE = { active: false };
|
|
9
|
+
/**
|
|
10
|
+
* Handles the OAuth 2.0 Token Introspection Endpoint (RFC 7662).
|
|
11
|
+
*
|
|
12
|
+
* Allows an authenticated client to determine the active state and
|
|
13
|
+
* metadata of a token (access token or refresh token). The response
|
|
14
|
+
* always includes at least `{ active: boolean }`.
|
|
15
|
+
*
|
|
16
|
+
* Supports the `token_type_hint` parameter to optimize lookup order.
|
|
17
|
+
* Both access tokens and refresh tokens are opaque values looked up
|
|
18
|
+
* by their SHA-256 hash in the database.
|
|
19
|
+
*
|
|
20
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7662
|
|
21
|
+
*/
|
|
9
22
|
var IntrospectController = class {
|
|
10
23
|
async handle(ctx) {
|
|
11
24
|
const manager = await ctx.containerResolver.make(SesameManager);
|
|
@@ -51,4 +64,5 @@ var IntrospectController = class {
|
|
|
51
64
|
return INACTIVE;
|
|
52
65
|
}
|
|
53
66
|
};
|
|
67
|
+
//#endregion
|
|
54
68
|
export { IntrospectController as default };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { i as OAuthAuthorizationCode } from "./sesame_manager-DYUSZ0NC.js";
|
|
2
|
+
import { t as TokenService } from "./token_service-DwnfAR9F.js";
|
|
3
|
+
import { DateTime } from "luxon";
|
|
4
|
+
import string from "@adonisjs/core/helpers/string";
|
|
5
|
+
//#region src/actions/issue_authorization_code.ts
|
|
6
|
+
/**
|
|
7
|
+
* Create and persist an authorization code in the database.
|
|
8
|
+
* Returns the raw (unhashed) code to be sent to the client.
|
|
9
|
+
*
|
|
10
|
+
* Shared between the authorize and consent flows to avoid
|
|
11
|
+
* duplicating the code-issuance logic.
|
|
12
|
+
*/
|
|
13
|
+
var IssueAuthorizationCodeAction = class {
|
|
14
|
+
/**
|
|
15
|
+
* Generate an opaque authorization code, store its SHA-256
|
|
16
|
+
* hash in the database, and return the raw value for the
|
|
17
|
+
* client redirect.
|
|
18
|
+
*/
|
|
19
|
+
async execute(manager, input) {
|
|
20
|
+
const tokenService = new TokenService(manager);
|
|
21
|
+
const raw = tokenService.generateOpaqueToken();
|
|
22
|
+
const hashed = tokenService.hashToken(raw);
|
|
23
|
+
const ttl = string.seconds.parse(manager.config.authorizationCodeTtl);
|
|
24
|
+
await OAuthAuthorizationCode.create({
|
|
25
|
+
id: crypto.randomUUID(),
|
|
26
|
+
code: hashed,
|
|
27
|
+
clientId: input.client.clientId,
|
|
28
|
+
userId: input.userId,
|
|
29
|
+
scopes: input.scopes,
|
|
30
|
+
redirectUri: input.redirectUri,
|
|
31
|
+
codeChallenge: input.codeChallenge ?? null,
|
|
32
|
+
codeChallengeMethod: input.codeChallengeMethod ?? null,
|
|
33
|
+
nonce: input.nonce ?? null,
|
|
34
|
+
expiresAt: DateTime.now().plus({ seconds: ttl })
|
|
35
|
+
});
|
|
36
|
+
return raw;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
export { IssueAuthorizationCodeAction as t };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import "./chunk-DF48asd8.js";
|
|
2
|
+
import { t as SesameManager } from "./sesame_manager-DYUSZ0NC.js";
|
|
3
|
+
import "./oauth_client-BSanvSql.js";
|
|
4
|
+
import "./oauth_error-C7UhDb2q.js";
|
|
5
|
+
import "./oauth_access_token-Cz_5gNBx.js";
|
|
6
|
+
//#region src/controllers/jwks_controller.ts
|
|
7
|
+
/**
|
|
8
|
+
* Serves the JSON Web Key Set (JWKS) containing public keys
|
|
9
|
+
* used to verify ID token signatures.
|
|
10
|
+
*
|
|
11
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7517
|
|
12
|
+
*/
|
|
13
|
+
var JwksController = class {
|
|
14
|
+
async handle(ctx) {
|
|
15
|
+
const manager = await ctx.containerResolver.make(SesameManager);
|
|
16
|
+
if (!manager.isOidcEnabled) {
|
|
17
|
+
ctx.response.status(404);
|
|
18
|
+
return { error: "OIDC is not configured" };
|
|
19
|
+
}
|
|
20
|
+
ctx.response.header("Cache-Control", "public, max-age=900");
|
|
21
|
+
ctx.response.header("Content-Type", "application/jwk-set+json");
|
|
22
|
+
return manager.keyService.getPublicJwks();
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
//#endregion
|
|
26
|
+
export { JwksController as default };
|
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import { t as
|
|
3
|
-
import { t as TokenService } from "./token_service-
|
|
1
|
+
import { t as OAuthClient } from "./oauth_client-BSanvSql.js";
|
|
2
|
+
import { t as OAuthAccessToken } from "./oauth_access_token-Cz_5gNBx.js";
|
|
3
|
+
import { t as TokenService } from "./token_service-DwnfAR9F.js";
|
|
4
4
|
import { DateTime } from "luxon";
|
|
5
5
|
import { RuntimeException } from "@adonisjs/core/exceptions";
|
|
6
6
|
import { errors } from "@adonisjs/auth";
|
|
7
|
+
//#region src/guard/guard.ts
|
|
8
|
+
/**
|
|
9
|
+
* OAuth 2.0 guard for `@adonisjs/auth`.
|
|
10
|
+
*
|
|
11
|
+
* Verifies opaque Bearer tokens against the database,
|
|
12
|
+
* checks revocation and expiry, loads the real User model
|
|
13
|
+
* via the provider, and exposes OAuth-specific data (scopes, clientId).
|
|
14
|
+
*/
|
|
7
15
|
var OAuthGuard = class {
|
|
8
16
|
driverName = "oauth";
|
|
9
17
|
authenticationAttempted = false;
|
|
@@ -91,6 +99,13 @@ var OAuthGuard = class {
|
|
|
91
99
|
hasAnyScope(...scopes) {
|
|
92
100
|
return scopes.some((s) => this.scopes.includes(s));
|
|
93
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Used internally by Japa's `loginAs` helper during testing.
|
|
104
|
+
* Creates a test client and access token in DB, then returns
|
|
105
|
+
* the authorization headers for the test HTTP client to use.
|
|
106
|
+
*
|
|
107
|
+
* @see https://docs.adonisjs.com/guides/auth/custom-auth-guard#implementing-the-guard
|
|
108
|
+
*/
|
|
94
109
|
async authenticateAsClient(user) {
|
|
95
110
|
const tokenService = new TokenService(this.#manager);
|
|
96
111
|
const defaultScopes = this.#manager.config.defaultScopes;
|
|
@@ -117,6 +132,12 @@ var OAuthGuard = class {
|
|
|
117
132
|
return { headers: { authorization: `Bearer ${raw}` } };
|
|
118
133
|
}
|
|
119
134
|
};
|
|
135
|
+
//#endregion
|
|
136
|
+
//#region src/guard/user_provider.ts
|
|
137
|
+
/**
|
|
138
|
+
* Lucid-based user provider for the OAuth guard.
|
|
139
|
+
* Lazily loads the model and wraps instances as guard users.
|
|
140
|
+
*/
|
|
120
141
|
var OAuthLucidUserProvider = class {
|
|
121
142
|
#model;
|
|
122
143
|
#options;
|
|
@@ -147,15 +168,24 @@ var OAuthLucidUserProvider = class {
|
|
|
147
168
|
return this.createUserForGuard(user);
|
|
148
169
|
}
|
|
149
170
|
};
|
|
171
|
+
//#endregion
|
|
172
|
+
//#region src/guard/main.ts
|
|
173
|
+
/**
|
|
174
|
+
* Configure the OAuth guard for `@adonisjs/auth`.
|
|
175
|
+
*/
|
|
150
176
|
function oauthGuard(config) {
|
|
151
177
|
return { async resolver(name, app) {
|
|
152
178
|
const emitter = await app.container.make("emitter");
|
|
153
|
-
const { SesameManager } = await import("./sesame_manager-
|
|
179
|
+
const { SesameManager } = await import("./sesame_manager-B1Jgq1v2.js");
|
|
154
180
|
const manager = await app.container.make(SesameManager);
|
|
155
181
|
return (ctx) => new OAuthGuard(name, ctx, emitter, config.provider, manager, config.resource);
|
|
156
182
|
} };
|
|
157
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
* Create a Lucid-based user provider for the OAuth guard.
|
|
186
|
+
*/
|
|
158
187
|
function oauthUserProvider(options) {
|
|
159
188
|
return new OAuthLucidUserProvider(options);
|
|
160
189
|
}
|
|
190
|
+
//#endregion
|
|
161
191
|
export { OAuthGuard as i, oauthUserProvider as n, OAuthLucidUserProvider as r, oauthGuard as t };
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import "./
|
|
3
|
-
import "./
|
|
4
|
-
import { l as E_SERVER_ERROR } from "./oauth_error-
|
|
1
|
+
import "./chunk-DF48asd8.js";
|
|
2
|
+
import { s as BUILTIN_SCOPES, t as SesameManager } from "./sesame_manager-DYUSZ0NC.js";
|
|
3
|
+
import "./oauth_client-BSanvSql.js";
|
|
4
|
+
import { l as E_SERVER_ERROR } from "./oauth_error-C7UhDb2q.js";
|
|
5
|
+
import "./oauth_access_token-Cz_5gNBx.js";
|
|
6
|
+
//#region src/controllers/metadata_controller.ts
|
|
5
7
|
const DISCOVERY_ROUTE_NAMES = {
|
|
6
8
|
authorization_endpoint: "sesame.authorize",
|
|
7
9
|
token_endpoint: "sesame.token",
|
|
@@ -9,6 +11,22 @@ const DISCOVERY_ROUTE_NAMES = {
|
|
|
9
11
|
introspection_endpoint: "sesame.introspect",
|
|
10
12
|
revocation_endpoint: "sesame.revoke"
|
|
11
13
|
};
|
|
14
|
+
const OIDC_DISCOVERY_ROUTE_NAMES = {
|
|
15
|
+
userinfo_endpoint: "sesame.userinfo",
|
|
16
|
+
jwks_uri: "sesame.jwks"
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Serves OAuth 2.0 discovery metadata documents.
|
|
20
|
+
*
|
|
21
|
+
* Exposes three well-known endpoints:
|
|
22
|
+
* - `authServer()` — OAuth Authorization Server Metadata (RFC 8414)
|
|
23
|
+
* - `oidc()` — OpenID Connect Discovery 1.0 (extends authServer metadata)
|
|
24
|
+
* - `protectedResource()` — OAuth Protected Resource Metadata (RFC 9728)
|
|
25
|
+
*
|
|
26
|
+
* @see https://datatracker.ietf.org/doc/html/rfc8414
|
|
27
|
+
* @see https://datatracker.ietf.org/doc/html/rfc9728
|
|
28
|
+
* @see https://openid.net/specs/openid-connect-discovery-1_0.html
|
|
29
|
+
*/
|
|
12
30
|
var MetadataController = class {
|
|
13
31
|
#assertDiscoveryRoutes(router, options) {
|
|
14
32
|
const requiredRoutes = [
|
|
@@ -21,6 +39,19 @@ var MetadataController = class {
|
|
|
21
39
|
const missingRoutes = requiredRoutes.filter((routeName) => !router.has(routeName));
|
|
22
40
|
if (missingRoutes.length > 0) throw new E_SERVER_ERROR(`OAuth discovery is misconfigured. Missing named route(s): ${missingRoutes.join(", ")}. Register OAuth routes with sesame.registerRoutes(router) before exposing well-known metadata.`);
|
|
23
41
|
}
|
|
42
|
+
#assertOidcDiscoveryRoutes(router) {
|
|
43
|
+
const missingRoutes = Object.values(OIDC_DISCOVERY_ROUTE_NAMES).filter((routeName) => !router.has(routeName));
|
|
44
|
+
if (missingRoutes.length > 0) throw new E_SERVER_ERROR(`OIDC discovery is misconfigured. Missing named route(s): ${missingRoutes.join(", ")}. Register OAuth routes with sesame.registerRoutes(router) and sesame.registerWellKnownRoutes(router) before exposing OpenID discovery.`);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* OAuth 2.0 Authorization Server Metadata (RFC 8414).
|
|
48
|
+
*
|
|
49
|
+
* Returns a JSON document describing the server's endpoints,
|
|
50
|
+
* supported grant types, response types, authentication methods,
|
|
51
|
+
* and PKCE support.
|
|
52
|
+
*
|
|
53
|
+
* @see https://datatracker.ietf.org/doc/html/rfc8414#section-2
|
|
54
|
+
*/
|
|
24
55
|
async authServer(ctx) {
|
|
25
56
|
const manager = await ctx.containerResolver.make(SesameManager);
|
|
26
57
|
const router = await ctx.containerResolver.make("router");
|
|
@@ -57,15 +88,60 @@ var MetadataController = class {
|
|
|
57
88
|
authorization_response_iss_parameter_supported: true
|
|
58
89
|
};
|
|
59
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* OpenID Connect Discovery 1.0 metadata.
|
|
93
|
+
*
|
|
94
|
+
* Extends the authorization server metadata with OIDC-specific
|
|
95
|
+
* fields like `subject_types_supported` and
|
|
96
|
+
* `id_token_signing_alg_values_supported`.
|
|
97
|
+
*
|
|
98
|
+
* @see https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
|
|
99
|
+
*/
|
|
60
100
|
async oidc(ctx) {
|
|
61
|
-
const base = await this.authServer(ctx);
|
|
62
101
|
const manager = await ctx.containerResolver.make(SesameManager);
|
|
102
|
+
if (!manager.isOidcEnabled) {
|
|
103
|
+
ctx.response.status(404);
|
|
104
|
+
return { error: "OIDC is not configured" };
|
|
105
|
+
}
|
|
106
|
+
const base = await this.authServer(ctx);
|
|
107
|
+
const router = await ctx.containerResolver.make("router");
|
|
108
|
+
const prefixUrl = manager.config.issuer;
|
|
109
|
+
this.#assertOidcDiscoveryRoutes(router);
|
|
63
110
|
return {
|
|
64
111
|
...base,
|
|
112
|
+
userinfo_endpoint: router.makeUrl("sesame.userinfo", {}, { prefixUrl }),
|
|
113
|
+
jwks_uri: router.makeUrl("sesame.jwks", {}, { prefixUrl }),
|
|
65
114
|
subject_types_supported: ["public"],
|
|
66
|
-
|
|
115
|
+
id_token_signing_alg_values_supported: ["RS256"],
|
|
116
|
+
scopes_supported: [...new Set([
|
|
117
|
+
"openid",
|
|
118
|
+
"profile",
|
|
119
|
+
"email",
|
|
120
|
+
...Object.keys(manager.config.scopes),
|
|
121
|
+
...BUILTIN_SCOPES
|
|
122
|
+
])],
|
|
123
|
+
claims_supported: [
|
|
124
|
+
"sub",
|
|
125
|
+
"iss",
|
|
126
|
+
"aud",
|
|
127
|
+
"exp",
|
|
128
|
+
"iat",
|
|
129
|
+
"nonce",
|
|
130
|
+
"at_hash"
|
|
131
|
+
],
|
|
132
|
+
response_types_supported: ["code"]
|
|
67
133
|
};
|
|
68
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* OAuth 2.0 Protected Resource Metadata (RFC 9728).
|
|
137
|
+
*
|
|
138
|
+
* Returns a JSON document that tells clients which authorization
|
|
139
|
+
* servers protect this resource, which scopes are available, and
|
|
140
|
+
* how to present bearer tokens. Used by MCP clients to discover
|
|
141
|
+
* the authorization server.
|
|
142
|
+
*
|
|
143
|
+
* @see https://datatracker.ietf.org/doc/html/rfc9728
|
|
144
|
+
*/
|
|
69
145
|
async protectedResource(ctx) {
|
|
70
146
|
const manager = await ctx.containerResolver.make(SesameManager);
|
|
71
147
|
const issuer = manager.config.issuer;
|
|
@@ -78,4 +154,5 @@ var MetadataController = class {
|
|
|
78
154
|
};
|
|
79
155
|
}
|
|
80
156
|
};
|
|
157
|
+
//#endregion
|
|
81
158
|
export { MetadataController as default };
|
|
@@ -1,5 +1,15 @@
|
|
|
1
|
-
import { n as
|
|
1
|
+
import { n as __decorate, r as json } from "./oauth_client-BSanvSql.js";
|
|
2
2
|
import { BaseModel, column } from "@adonisjs/lucid/orm";
|
|
3
|
+
//#region src/models/oauth_access_token.ts
|
|
4
|
+
/**
|
|
5
|
+
* Database record for an issued OAuth 2.0 access token.
|
|
6
|
+
*
|
|
7
|
+
* Access tokens are opaque random values. Only the SHA-256 hash
|
|
8
|
+
* is stored so raw tokens cannot be reconstructed from a DB leak.
|
|
9
|
+
* A token is considered revoked when `revokedAt` is set.
|
|
10
|
+
*
|
|
11
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7662
|
|
12
|
+
*/
|
|
3
13
|
var OAuthAccessToken = class extends BaseModel {
|
|
4
14
|
static table = "oauth_access_tokens";
|
|
5
15
|
};
|
|
@@ -15,4 +25,5 @@ __decorate([column.dateTime({
|
|
|
15
25
|
autoCreate: true,
|
|
16
26
|
autoUpdate: true
|
|
17
27
|
})], OAuthAccessToken.prototype, "updatedAt", void 0);
|
|
28
|
+
//#endregion
|
|
18
29
|
export { OAuthAccessToken as t };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { BaseModel, column } from "@adonisjs/lucid/orm";
|
|
2
|
+
//#region src/decorators.ts
|
|
3
|
+
/**
|
|
4
|
+
* Column decorator for JSON values (arrays, objects).
|
|
5
|
+
*
|
|
6
|
+
* Lucid ORM doesn't handle JSON serialization automatically —
|
|
7
|
+
* `prepare` stringifies before INSERT/UPDATE, `consume` parses
|
|
8
|
+
* after SELECT. The typeof check in consume handles both drivers
|
|
9
|
+
* that return strings (SQLite, MySQL) and parsed objects (PostgreSQL JSONB).
|
|
10
|
+
*/
|
|
11
|
+
function json(options) {
|
|
12
|
+
return column({
|
|
13
|
+
...options,
|
|
14
|
+
prepare: (value) => value == null ? null : JSON.stringify(value),
|
|
15
|
+
consume: (value) => value == null ? null : typeof value === "string" ? JSON.parse(value) : value
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region \0@oxc-project+runtime@0.115.0/helpers/decorate.js
|
|
20
|
+
function __decorate(decorators, target, key, desc) {
|
|
21
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
22
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
23
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
24
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/models/oauth_client.ts
|
|
28
|
+
/**
|
|
29
|
+
* Represents a registered OAuth 2.0 client (RFC 6749 §2).
|
|
30
|
+
*
|
|
31
|
+
* Clients can be either confidential (with a hashed secret) or
|
|
32
|
+
* public (no secret, e.g. SPAs, native apps). Public clients must
|
|
33
|
+
* use PKCE (RFC 7636) for authorization code exchanges.
|
|
34
|
+
*
|
|
35
|
+
* Clients may be created manually or via dynamic client registration
|
|
36
|
+
* (RFC 7591) through the `/oauth/register` endpoint.
|
|
37
|
+
*
|
|
38
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6749#section-2
|
|
39
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7591
|
|
40
|
+
*/
|
|
41
|
+
var OAuthClient = class extends BaseModel {
|
|
42
|
+
static table = "oauth_clients";
|
|
43
|
+
};
|
|
44
|
+
__decorate([column({ isPrimary: true })], OAuthClient.prototype, "id", void 0);
|
|
45
|
+
__decorate([column()], OAuthClient.prototype, "clientId", void 0);
|
|
46
|
+
__decorate([column({ serializeAs: null })], OAuthClient.prototype, "clientSecret", void 0);
|
|
47
|
+
__decorate([column()], OAuthClient.prototype, "name", void 0);
|
|
48
|
+
__decorate([json()], OAuthClient.prototype, "redirectUris", void 0);
|
|
49
|
+
__decorate([json()], OAuthClient.prototype, "scopes", void 0);
|
|
50
|
+
__decorate([json()], OAuthClient.prototype, "grantTypes", void 0);
|
|
51
|
+
__decorate([column()], OAuthClient.prototype, "isPublic", void 0);
|
|
52
|
+
__decorate([column()], OAuthClient.prototype, "isDisabled", void 0);
|
|
53
|
+
__decorate([column()], OAuthClient.prototype, "requirePkce", void 0);
|
|
54
|
+
__decorate([column()], OAuthClient.prototype, "type", void 0);
|
|
55
|
+
__decorate([json()], OAuthClient.prototype, "metadata", void 0);
|
|
56
|
+
__decorate([column()], OAuthClient.prototype, "userId", void 0);
|
|
57
|
+
__decorate([column.dateTime({ autoCreate: true })], OAuthClient.prototype, "createdAt", void 0);
|
|
58
|
+
__decorate([column.dateTime({
|
|
59
|
+
autoCreate: true,
|
|
60
|
+
autoUpdate: true
|
|
61
|
+
})], OAuthClient.prototype, "updatedAt", void 0);
|
|
62
|
+
//#endregion
|
|
63
|
+
export { __decorate as n, json as r, OAuthClient as t };
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { Exception } from "@adonisjs/core/exceptions";
|
|
2
|
+
//#region src/oauth_error.ts
|
|
3
|
+
/**
|
|
4
|
+
* OAuth 2.0 error classes following the error codes defined in
|
|
5
|
+
* RFC 6749 §5.2 (https://datatracker.ietf.org/doc/html/rfc6749#section-5.2)
|
|
6
|
+
* and RFC 7591 §3.2.2 (https://datatracker.ietf.org/doc/html/rfc7591#section-3.2.2).
|
|
7
|
+
*
|
|
8
|
+
* Each error class extends AdonisJS Exception and self-renders via
|
|
9
|
+
* the `handle()` method, producing a standard OAuth JSON error response.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Base class for all OAuth errors. Extends AdonisJS Exception
|
|
13
|
+
* and renders the standard OAuth error response format:
|
|
14
|
+
* `{ error: "<oauth_code>", error_description: "<message>" }`.
|
|
15
|
+
*
|
|
16
|
+
* Subclasses declare a static `oauthCode` matching the `error` field
|
|
17
|
+
* defined by the OAuth 2.0 spec (e.g. `invalid_request`, `invalid_client`).
|
|
18
|
+
*/
|
|
19
|
+
var OAuthError = class extends Exception {
|
|
20
|
+
static oauthCode;
|
|
21
|
+
get oauthCode() {
|
|
22
|
+
return this.constructor.oauthCode;
|
|
23
|
+
}
|
|
24
|
+
handle(error, ctx) {
|
|
25
|
+
ctx.response.status(error.status).json({
|
|
26
|
+
error: error.oauthCode,
|
|
27
|
+
error_description: error.message
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* The request is missing a required parameter, includes an unsupported
|
|
33
|
+
* parameter value, repeats a parameter, or is otherwise malformed.
|
|
34
|
+
*
|
|
35
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
|
|
36
|
+
*/
|
|
37
|
+
const E_INVALID_REQUEST = class extends OAuthError {
|
|
38
|
+
static status = 400;
|
|
39
|
+
static code = "E_INVALID_REQUEST";
|
|
40
|
+
static message = "Invalid request";
|
|
41
|
+
static oauthCode = "invalid_request";
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Client authentication failed (e.g. unknown client, no client
|
|
45
|
+
* authentication included, or unsupported authentication method).
|
|
46
|
+
*
|
|
47
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
|
|
48
|
+
*/
|
|
49
|
+
const E_INVALID_CLIENT = class extends OAuthError {
|
|
50
|
+
static status = 401;
|
|
51
|
+
static code = "E_INVALID_CLIENT";
|
|
52
|
+
static message = "Invalid client";
|
|
53
|
+
static oauthCode = "invalid_client";
|
|
54
|
+
/**
|
|
55
|
+
* If the client attempted to authenticate via the Authorization header
|
|
56
|
+
* (Basic auth), the server MUST include WWW-Authenticate: Basic.
|
|
57
|
+
*
|
|
58
|
+
* @see https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12#section-3.2.4
|
|
59
|
+
*/
|
|
60
|
+
handle(error, ctx) {
|
|
61
|
+
if (ctx.request.header("authorization")?.startsWith("Basic ")) ctx.response.header("WWW-Authenticate", "Basic");
|
|
62
|
+
super.handle(error, ctx);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* The provided authorization grant (authorization code, refresh token,
|
|
67
|
+
* resource owner credentials) is invalid, expired, revoked, or does
|
|
68
|
+
* not match the redirection URI used in the authorization request.
|
|
69
|
+
*
|
|
70
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
|
|
71
|
+
*/
|
|
72
|
+
const E_INVALID_GRANT = class extends OAuthError {
|
|
73
|
+
static status = 400;
|
|
74
|
+
static code = "E_INVALID_GRANT";
|
|
75
|
+
static message = "Invalid grant";
|
|
76
|
+
static oauthCode = "invalid_grant";
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* The requested scope is invalid, unknown, malformed, or exceeds
|
|
80
|
+
* the scope granted by the resource owner.
|
|
81
|
+
*
|
|
82
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
|
|
83
|
+
*/
|
|
84
|
+
const E_INVALID_SCOPE = class extends OAuthError {
|
|
85
|
+
static status = 400;
|
|
86
|
+
static code = "E_INVALID_SCOPE";
|
|
87
|
+
static message = "Invalid scope";
|
|
88
|
+
static oauthCode = "invalid_scope";
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* The access token provided is expired, revoked, malformed,
|
|
92
|
+
* or invalid for other reasons.
|
|
93
|
+
*
|
|
94
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6750#section-3.1
|
|
95
|
+
*/
|
|
96
|
+
const E_INVALID_TOKEN = class extends OAuthError {
|
|
97
|
+
static status = 401;
|
|
98
|
+
static code = "E_INVALID_TOKEN";
|
|
99
|
+
static message = "Invalid token";
|
|
100
|
+
static oauthCode = "invalid_token";
|
|
101
|
+
handle(error, ctx) {
|
|
102
|
+
ctx.response.header("WWW-Authenticate", `Bearer error="invalid_token", error_description="${error.message}"`);
|
|
103
|
+
super.handle(error, ctx);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* The authorization grant type is not supported by the
|
|
108
|
+
* authorization server.
|
|
109
|
+
*
|
|
110
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
|
|
111
|
+
*/
|
|
112
|
+
const E_UNSUPPORTED_GRANT_TYPE = class extends OAuthError {
|
|
113
|
+
static status = 400;
|
|
114
|
+
static code = "E_UNSUPPORTED_GRANT_TYPE";
|
|
115
|
+
static message = "Unsupported grant type";
|
|
116
|
+
static oauthCode = "unsupported_grant_type";
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* The authorization server does not support obtaining an
|
|
120
|
+
* authorization code using this response type.
|
|
121
|
+
*
|
|
122
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1
|
|
123
|
+
*/
|
|
124
|
+
const E_UNSUPPORTED_RESPONSE_TYPE = class extends OAuthError {
|
|
125
|
+
static status = 400;
|
|
126
|
+
static code = "E_UNSUPPORTED_RESPONSE_TYPE";
|
|
127
|
+
static message = "Unsupported response type";
|
|
128
|
+
static oauthCode = "unsupported_response_type";
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* The resource owner or authorization server denied the request.
|
|
132
|
+
*
|
|
133
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1
|
|
134
|
+
*/
|
|
135
|
+
const E_ACCESS_DENIED = class extends OAuthError {
|
|
136
|
+
static status = 403;
|
|
137
|
+
static code = "E_ACCESS_DENIED";
|
|
138
|
+
static message = "Access denied";
|
|
139
|
+
static oauthCode = "access_denied";
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* The client metadata value is invalid, as defined in the dynamic
|
|
143
|
+
* client registration protocol.
|
|
144
|
+
*
|
|
145
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7591#section-3.2.2
|
|
146
|
+
*/
|
|
147
|
+
const E_INVALID_CLIENT_METADATA = class extends OAuthError {
|
|
148
|
+
static status = 400;
|
|
149
|
+
static code = "E_INVALID_CLIENT_METADATA";
|
|
150
|
+
static message = "Invalid client metadata";
|
|
151
|
+
static oauthCode = "invalid_client_metadata";
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* The authorization server encountered an unexpected condition
|
|
155
|
+
* that prevented it from fulfilling the request.
|
|
156
|
+
*
|
|
157
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1
|
|
158
|
+
*/
|
|
159
|
+
const E_SERVER_ERROR = class extends OAuthError {
|
|
160
|
+
static status = 500;
|
|
161
|
+
static code = "E_SERVER_ERROR";
|
|
162
|
+
static message = "Server error";
|
|
163
|
+
static oauthCode = "server_error";
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* The access token does not have the required scope(s) to access
|
|
167
|
+
* the protected resource. Returns 403 with a WWW-Authenticate header
|
|
168
|
+
* per RFC 6750 §3.1.
|
|
169
|
+
*
|
|
170
|
+
* @see https://datatracker.ietf.org/doc/html/rfc6750#section-3.1
|
|
171
|
+
*/
|
|
172
|
+
const E_INSUFFICIENT_SCOPE = class extends OAuthError {
|
|
173
|
+
static status = 403;
|
|
174
|
+
static code = "E_INSUFFICIENT_SCOPE";
|
|
175
|
+
static message = "Insufficient scope";
|
|
176
|
+
static oauthCode = "insufficient_scope";
|
|
177
|
+
missingScopes;
|
|
178
|
+
constructor(missingScopes, message) {
|
|
179
|
+
super(message ?? "The token does not have the required scope(s)");
|
|
180
|
+
this.missingScopes = missingScopes;
|
|
181
|
+
}
|
|
182
|
+
handle(error, ctx) {
|
|
183
|
+
const scope = error.missingScopes.join(" ");
|
|
184
|
+
ctx.response.header("WWW-Authenticate", `Bearer error="insufficient_scope", error_description="${error.message}", scope="${scope}"`);
|
|
185
|
+
super.handle(error, ctx);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
//#endregion
|
|
189
|
+
export { E_INVALID_GRANT as a, E_INVALID_TOKEN as c, E_UNSUPPORTED_RESPONSE_TYPE as d, E_INVALID_CLIENT_METADATA as i, E_SERVER_ERROR as l, E_INSUFFICIENT_SCOPE as n, E_INVALID_REQUEST as o, E_INVALID_CLIENT as r, E_INVALID_SCOPE as s, E_ACCESS_DENIED as t, E_UNSUPPORTED_GRANT_TYPE as u };
|
|
@@ -1,14 +1,25 @@
|
|
|
1
|
-
import
|
|
2
|
-
import "../
|
|
3
|
-
import "../
|
|
1
|
+
import "../chunk-DF48asd8.js";
|
|
2
|
+
import { t as SesameManager } from "../sesame_manager-DYUSZ0NC.js";
|
|
3
|
+
import "../oauth_client-BSanvSql.js";
|
|
4
|
+
import "../oauth_error-C7UhDb2q.js";
|
|
5
|
+
import "../oauth_access_token-Cz_5gNBx.js";
|
|
6
|
+
//#region providers/sesame_provider.ts
|
|
7
|
+
/**
|
|
8
|
+
* AdonisJS service provider for the Sésame OAuth 2.1 server.
|
|
9
|
+
*/
|
|
4
10
|
var SesameProvider = class {
|
|
5
11
|
constructor(app) {
|
|
6
12
|
this.app = app;
|
|
7
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Register `SesameManager` as a singleton binding.
|
|
16
|
+
* The manager is resolved from the `sesame` config key.
|
|
17
|
+
*/
|
|
8
18
|
register() {
|
|
9
19
|
this.app.container.singleton(SesameManager, async () => {
|
|
10
20
|
return new SesameManager(this.app.config.get("sesame"), await this.app.container.make("router"));
|
|
11
21
|
});
|
|
12
22
|
}
|
|
13
23
|
};
|
|
24
|
+
//#endregion
|
|
14
25
|
export { SesameProvider as default };
|