@julr/sesame 0.5.1 → 0.7.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.
Files changed (97) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +470 -64
  3. package/build/authorize_controller-sCZIjnc-.js +251 -0
  4. package/build/{client_info_controller-BucHGx4u.js → client_info_controller-B5A3tpbk.js} +11 -4
  5. package/build/commands/sesame_client.d.ts +20 -0
  6. package/build/commands/sesame_key.d.ts +12 -0
  7. package/build/commands/sesame_purge.d.ts +0 -2
  8. package/build/commands/sesame_purge.js +12 -3
  9. package/build/configure-t9q3KonY.js +31 -0
  10. package/build/configure.js +1 -24
  11. package/build/consent_controller-ChBboaSd.js +96 -0
  12. package/build/consent_retry-DMkfhmk9.js +41 -0
  13. package/build/{decorate-BKZEjPRg.js → decorate-RQD1h28J.js} +3 -9
  14. package/build/id_token_service-BtBUiL_n.js +54 -0
  15. package/build/index.d.ts +2 -8
  16. package/build/index.js +59 -10
  17. package/build/{introspect_controller-6bRt9sZt.js → introspect_controller-LVYGWhMj.js} +28 -10
  18. package/build/issue_authorization_code-Dr4-bbMp.js +39 -0
  19. package/build/jwks_controller-4HUVS_HC.js +22 -0
  20. package/build/{main-EbeMS5S9.js → main-Dx9kZv07.js} +35 -43
  21. package/build/{metadata_controller-DeaMRnUr.js → metadata_controller-hwfmxlF7.js} +81 -6
  22. package/build/oauth_error-CvxtZvjp.js +189 -0
  23. package/build/providers/sesame_provider.d.ts +1 -1
  24. package/build/providers/sesame_provider.js +17 -6
  25. package/build/{register_controller-sIJ1rxdM.js → register_controller-Cdk3c32j.js} +44 -8
  26. package/build/revoke_controller-Daz4Yqfs.js +48 -0
  27. package/build/services/main.js +3 -3
  28. package/build/sesame_manager-CeEmlzba.js +515 -0
  29. package/build/sesame_manager-DQxvsTEq.js +2 -0
  30. package/build/src/actions/authorize.d.ts +46 -0
  31. package/build/src/actions/exchange_authorization_code.d.ts +34 -0
  32. package/build/src/actions/exchange_client_credentials.d.ts +28 -0
  33. package/build/src/actions/exchange_refresh_token.d.ts +59 -0
  34. package/build/src/actions/issue_authorization_code.d.ts +26 -0
  35. package/build/src/controllers/authorize_controller.d.ts +18 -17
  36. package/build/src/controllers/consent_controller.d.ts +5 -0
  37. package/build/src/controllers/jwks_controller.d.ts +14 -0
  38. package/build/src/controllers/metadata_controller.d.ts +10 -3
  39. package/build/src/controllers/register_controller.d.ts +30 -30
  40. package/build/src/controllers/token_controller.d.ts +8 -5
  41. package/build/src/controllers/userinfo_controller.d.ts +14 -0
  42. package/build/src/guard/guard.d.ts +1 -1
  43. package/build/src/guard/lucid.d.ts +8 -0
  44. package/build/src/guard/lucid.js +46 -0
  45. package/build/src/guard/main.d.ts +2 -9
  46. package/build/src/guard/main.js +2 -6
  47. package/build/src/guard/types.d.ts +0 -9
  48. package/build/src/guard/user_provider.d.ts +9 -1
  49. package/build/src/middleware/any_scope_middleware.js +10 -1
  50. package/build/src/middleware/scope_middleware.js +10 -1
  51. package/build/src/models/oauth_authorization_code.d.ts +1 -0
  52. package/build/src/models/oauth_pending_authorization_request.d.ts +1 -0
  53. package/build/src/oauth_error.d.ts +74 -74
  54. package/build/src/routes.d.ts +3 -1
  55. package/build/src/services/client_service.d.ts +5 -2
  56. package/build/src/services/id_token_service.d.ts +30 -0
  57. package/build/src/services/key_service.d.ts +20 -0
  58. package/build/src/sesame_manager.d.ts +56 -4
  59. package/build/src/storage/consent_retry.d.ts +4 -0
  60. package/build/src/storage/drivers/kysely.d.ts +166 -0
  61. package/build/src/storage/drivers/kysely.js +480 -0
  62. package/build/src/storage/drivers/lucid.d.ts +162 -0
  63. package/build/src/storage/drivers/lucid.js +549 -0
  64. package/build/src/storage/migrations/kysely.d.ts +6 -0
  65. package/build/src/storage/types.d.ts +197 -0
  66. package/build/src/storage/types.js +1 -0
  67. package/build/src/stores.d.ts +21 -0
  68. package/build/src/types.d.ts +120 -0
  69. package/build/src/types.js +2 -0
  70. package/build/stubs/config/sesame.stub +4 -1
  71. package/build/stubs/config/sesame_kysely.stub +35 -0
  72. package/build/stubs/main.ts +5 -0
  73. package/build/stubs/migrations/create_oauth_authorization_codes_table.stub +1 -0
  74. package/build/stubs/migrations/create_oauth_pending_authorization_requests_table.stub +1 -0
  75. package/build/stubs/migrations/create_oauth_refresh_tokens_table.stub +1 -1
  76. package/build/stubs/migrations/kysely/create_oauth_tables.stub +151 -0
  77. package/build/taze.config.d.ts +2 -0
  78. package/build/token_controller-DRatCQNT.js +492 -0
  79. package/build/token_service-DDQ3Dxaj.js +59 -0
  80. package/build/types-DEtn2Zdb.js +75 -0
  81. package/build/userinfo_controller-YwN26wK-.js +37 -0
  82. package/build/vite.config.d.ts +2 -0
  83. package/package.json +55 -54
  84. package/build/authorize_controller-YUfAy-R2.js +0 -138
  85. package/build/client_service-WTNMqWzY.js +0 -65
  86. package/build/consent_controller-Dprwd1ed.js +0 -85
  87. package/build/oauth_access_token-bsoM5KeU.js +0 -18
  88. package/build/oauth_client-BIoY5jBR.js +0 -24
  89. package/build/oauth_error-CnJ3L8tf.js +0 -94
  90. package/build/revoke_controller-D6isoQCi.js +0 -41
  91. package/build/sesame_manager-Bu4MHqZV.js +0 -4
  92. package/build/sesame_manager-DwDZy5Vy.js +0 -167
  93. package/build/src/grants/authorization_code_grant.d.ts +0 -23
  94. package/build/src/grants/client_credentials_grant.d.ts +0 -23
  95. package/build/src/grants/refresh_token_grant.d.ts +0 -27
  96. package/build/token_controller-DzcrLMyS.js +0 -194
  97. package/build/token_service-fhoA4slP.js +0 -31
@@ -1,14 +1,25 @@
1
- import { t as SesameManager } from "../sesame_manager-DwDZy5Vy.js";
2
- import "../decorate-BKZEjPRg.js";
3
- import "../oauth_access_token-bsoM5KeU.js";
1
+ import { t as SesameManager } from "../sesame_manager-CeEmlzba.js";
2
+ //#region providers/sesame_provider.ts
3
+ /**
4
+ * AdonisJS service provider for the Sésame OAuth 2.1 server.
5
+ */
4
6
  var SesameProvider = class {
7
+ #app;
5
8
  constructor(app) {
6
- this.app = app;
9
+ this.#app = app;
7
10
  }
11
+ /**
12
+ * Register `SesameManager` as a singleton binding.
13
+ * The manager is resolved from the `sesame` config key.
14
+ */
8
15
  register() {
9
- this.app.container.singleton(SesameManager, async () => {
10
- return new SesameManager(this.app.config.get("sesame"), await this.app.container.make("router"));
16
+ this.#app.container.singleton(SesameManager, async () => {
17
+ const config = this.#app.config.get("sesame");
18
+ const router = await this.#app.container.make("router");
19
+ const store = await config.store.resolver(this.#app);
20
+ return new SesameManager(config, router, store);
11
21
  });
12
22
  }
13
23
  };
24
+ //#endregion
14
25
  export { SesameProvider as default };
@@ -1,10 +1,7 @@
1
- import { t as SesameManager } from "./sesame_manager-DwDZy5Vy.js";
2
- import "./decorate-BKZEjPRg.js";
3
- import "./oauth_access_token-bsoM5KeU.js";
4
- import { i as E_INVALID_CLIENT_METADATA, o as E_INVALID_REQUEST, s as E_INVALID_SCOPE, t as E_ACCESS_DENIED } from "./oauth_error-CnJ3L8tf.js";
5
- import { t as OAuthClient } from "./oauth_client-BIoY5jBR.js";
6
- import { t as ClientService } from "./client_service-WTNMqWzY.js";
1
+ import { i as E_INVALID_CLIENT_METADATA, o as E_INVALID_REQUEST, s as E_INVALID_SCOPE, t as E_ACCESS_DENIED } from "./oauth_error-CvxtZvjp.js";
2
+ import { n as ClientService, t as SesameManager } from "./sesame_manager-CeEmlzba.js";
7
3
  import vine from "@vinejs/vine";
4
+ //#region src/rules.ts
8
5
  const DANGEROUS_SCHEMES = [
9
6
  "javascript:",
10
7
  "data:",
@@ -15,6 +12,10 @@ const LOCALHOST_HOSTS = [
15
12
  "127.0.0.1",
16
13
  "[::1]"
17
14
  ];
15
+ /**
16
+ * Validates a redirect URI per OAuth 2.1 / RFC 8252 rules.
17
+ * Blocks fragments, dangerous schemes, and requires HTTPS for non-localhost hosts.
18
+ */
18
19
  const redirectUriRule = vine.createRule((value, _options, field) => {
19
20
  let parsed;
20
21
  try {
@@ -33,11 +34,40 @@ const redirectUriRule = vine.createRule((value, _options, field) => {
33
34
  }
34
35
  if (parsed.protocol === "http:" && !LOCALHOST_HOSTS.includes(parsed.hostname)) field.report("Redirect URI must use HTTPS for non-localhost hosts", "redirectUri", field);
35
36
  });
37
+ /**
38
+ * Blocks dangerous URI schemes for metadata URIs (client_uri, logo_uri, etc.).
39
+ *
40
+ * RFC 7591 §5 says the server MAY verify that metadata URIs match the
41
+ * host+scheme of redirect_uris, but this is NOT required.
42
+ *
43
+ * We intentionally skip this check because it breaks legitimate CLI/desktop clients
44
+ * (e.g. OpenCode, Claude Code) that use localhost redirect URIs but have a
45
+ * different `client_uri` pointing to their website.
46
+ *
47
+ * Maybe we can add an option to enable this check in the future if needed.
48
+ *
49
+ * @see https://datatracker.ietf.org/doc/html/rfc7591#section-5
50
+ */
36
51
  const metadataUriRule = vine.createRule((value, _options, field) => {
37
52
  const parsed = new URL(value);
38
53
  if (DANGEROUS_SCHEMES.includes(parsed.protocol)) field.report("{{ field }} uses a disallowed scheme", "metadataUri", field);
39
54
  });
55
+ //#endregion
56
+ //#region src/controllers/register_controller.ts
40
57
  const metadataUrl = vine.string().url({ require_protocol: true }).use(metadataUriRule()).optional();
58
+ /**
59
+ * Handles the OAuth 2.0 Dynamic Client Registration Endpoint (RFC 7591).
60
+ *
61
+ * Allows clients to register themselves with the authorization server
62
+ * by providing metadata such as `redirect_uris`, `grant_types`, and
63
+ * `token_endpoint_auth_method`. Returns the assigned `client_id` and
64
+ * optionally a `client_secret` for confidential clients.
65
+ *
66
+ * Can be configured to require authentication or allow public
67
+ * registration (useful for MCP where clients self-register).
68
+ *
69
+ * @see https://datatracker.ietf.org/doc/html/rfc7591
70
+ */
41
71
  var RegisterController = class RegisterController {
42
72
  static validator = vine.create(vine.object({
43
73
  redirect_uris: vine.array(vine.string().use(redirectUriRule())).minLength(1),
@@ -72,11 +102,12 @@ var RegisterController = class RegisterController {
72
102
  const clientService = new ClientService();
73
103
  const tokenEndpointAuthMethod = body.token_endpoint_auth_method ?? "client_secret_basic";
74
104
  const isPublic = tokenEndpointAuthMethod === "none";
75
- const grantTypes = body.grant_types ?? ["authorization_code"];
105
+ const grantTypes = body.grant_types ?? ["authorization_code", "refresh_token"];
76
106
  const responseTypes = body.response_types ?? ["code"];
77
107
  const scopes = body.scope ? body.scope.split(" ") : manager.config.defaultScopes;
78
108
  const invalidScopes = manager.validateScopes(scopes);
79
109
  if (invalidScopes.length > 0) throw new E_INVALID_SCOPE(`Unknown scopes: ${invalidScopes.join(", ")}`);
110
+ if (manager.usesOidcScopes(scopes) && !manager.isOidcEnabled) throw new E_INVALID_SCOPE("OIDC scopes require OIDC to be configured (set jwk and oidcProvider in config)");
80
111
  const clientName = body.client_name ?? "Unnamed Client";
81
112
  for (const gt of grantTypes) if (!manager.isGrantTypeEnabled(gt)) throw new E_INVALID_CLIENT_METADATA(`Unsupported grant type: ${gt}`);
82
113
  if (responseTypes.some((rt) => rt !== "code")) throw new E_INVALID_CLIENT_METADATA("Only \"code\" response type is supported");
@@ -94,7 +125,7 @@ var RegisterController = class RegisterController {
94
125
  ...body.software_id ? { software_id: body.software_id } : {},
95
126
  ...body.software_version ? { software_version: body.software_version } : {}
96
127
  };
97
- await OAuthClient.create({
128
+ await manager.store.createClient({
98
129
  id: crypto.randomUUID(),
99
130
  clientId,
100
131
  clientSecret: hashedSecret,
@@ -111,6 +142,10 @@ var RegisterController = class RegisterController {
111
142
  });
112
143
  ctx.response.header("Cache-Control", "no-store");
113
144
  ctx.response.status(201);
145
+ /**
146
+ * RFC 7591 §3.2.1 requires the response to include ALL registered
147
+ * metadata about this client, including fields provisioned by the server.
148
+ */
114
149
  return {
115
150
  client_id: clientId,
116
151
  ...clientSecret ? { client_secret: clientSecret } : {},
@@ -123,4 +158,5 @@ var RegisterController = class RegisterController {
123
158
  };
124
159
  }
125
160
  };
161
+ //#endregion
126
162
  export { RegisterController as default };
@@ -0,0 +1,48 @@
1
+ import { n as ClientService, t as SesameManager } from "./sesame_manager-CeEmlzba.js";
2
+ import { t as TokenService } from "./token_service-DDQ3Dxaj.js";
3
+ import { DateTime } from "luxon";
4
+ //#region src/controllers/revoke_controller.ts
5
+ /**
6
+ * Handles the OAuth 2.0 Token Revocation Endpoint (RFC 7009).
7
+ *
8
+ * Allows an authenticated client to revoke an access token or
9
+ * refresh token. Always responds with HTTP 200, even if the token
10
+ * was already revoked or not found (to prevent information leakage).
11
+ *
12
+ * When revoking a refresh token, the associated access token is
13
+ * also revoked as recommended by RFC 7009 §2.1.
14
+ *
15
+ * @see https://datatracker.ietf.org/doc/html/rfc7009
16
+ */
17
+ var RevokeController = class {
18
+ async handle(ctx) {
19
+ const manager = await ctx.containerResolver.make(SesameManager);
20
+ const clientService = new ClientService(manager);
21
+ const store = manager.store;
22
+ const client = await clientService.authenticateClient({
23
+ authorizationHeader: ctx.request.header("authorization"),
24
+ bodyClientId: ctx.request.body().client_id,
25
+ bodyClientSecret: ctx.request.body().client_secret
26
+ });
27
+ const token = ctx.request.body().token;
28
+ if (!token) return ctx.response.ok({});
29
+ const tokenTypeHint = ctx.request.body().token_type_hint;
30
+ const hashed = new TokenService(manager).hashToken(token);
31
+ if (!tokenTypeHint || tokenTypeHint === "access_token") {
32
+ if (await store.revokeAccessToken({
33
+ hash: hashed,
34
+ clientId: client.clientId,
35
+ now: DateTime.now()
36
+ })) return ctx.response.ok({});
37
+ if (tokenTypeHint === "access_token") return ctx.response.ok({});
38
+ }
39
+ if (!tokenTypeHint || tokenTypeHint === "refresh_token") await store.revokeRefreshToken({
40
+ hash: hashed,
41
+ clientId: client.clientId,
42
+ now: DateTime.now()
43
+ });
44
+ return ctx.response.ok({});
45
+ }
46
+ };
47
+ //#endregion
48
+ export { RevokeController as default };
@@ -1,9 +1,9 @@
1
- import { t as SesameManager } from "../sesame_manager-DwDZy5Vy.js";
2
- import "../decorate-BKZEjPRg.js";
3
- import "../oauth_access_token-bsoM5KeU.js";
1
+ import { t as SesameManager } from "../sesame_manager-CeEmlzba.js";
4
2
  import app from "@adonisjs/core/services/app";
3
+ //#region services/main.ts
5
4
  let sesame;
6
5
  await app.booted(async () => {
7
6
  sesame = await app.container.make(SesameManager);
8
7
  });
8
+ //#endregion
9
9
  export { sesame as default };