@julr/sesame 0.6.0 → 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 (70) hide show
  1. package/README.md +69 -6
  2. package/build/{authorize_controller-BiycO4be.js → authorize_controller-sCZIjnc-.js} +10 -10
  3. package/build/{client_info_controller-AcOG8lWu.js → client_info_controller-B5A3tpbk.js} +3 -4
  4. package/build/commands/sesame_key.d.ts +1 -1
  5. package/build/commands/sesame_purge.js +2 -5
  6. package/build/{configure-DkDkIlt8.js → configure-t9q3KonY.js} +7 -3
  7. package/build/configure.js +1 -2
  8. package/build/{consent_controller-Dsdhv6-f.js → consent_controller-ChBboaSd.js} +17 -29
  9. package/build/consent_retry-DMkfhmk9.js +41 -0
  10. package/build/decorate-RQD1h28J.js +9 -0
  11. package/build/{id_token_service-CpTzOUDe.js → id_token_service-BtBUiL_n.js} +1 -1
  12. package/build/index.d.ts +2 -8
  13. package/build/index.js +38 -9
  14. package/build/{introspect_controller-DvOp9scr.js → introspect_controller-LVYGWhMj.js} +13 -9
  15. package/build/{issue_authorization_code-B9ERu1uO.js → issue_authorization_code-Dr4-bbMp.js} +2 -3
  16. package/build/{jwks_controller-keo4kBZc.js → jwks_controller-4HUVS_HC.js} +1 -5
  17. package/build/{main-DGBJhq3E.js → main-Dx9kZv07.js} +14 -52
  18. package/build/{metadata_controller-BVsTo0Gp.js → metadata_controller-hwfmxlF7.js} +4 -6
  19. package/build/providers/sesame_provider.d.ts +1 -1
  20. package/build/providers/sesame_provider.js +8 -8
  21. package/build/{register_controller-gbq7p8a5.js → register_controller-Cdk3c32j.js} +3 -6
  22. package/build/{revoke_controller-z_ghrEB7.js → revoke_controller-Daz4Yqfs.js} +15 -21
  23. package/build/services/main.js +1 -5
  24. package/build/{sesame_manager-DYUSZ0NC.js → sesame_manager-CeEmlzba.js} +78 -256
  25. package/build/sesame_manager-DQxvsTEq.js +2 -0
  26. package/build/src/actions/exchange_authorization_code.d.ts +5 -5
  27. package/build/src/actions/exchange_client_credentials.d.ts +3 -3
  28. package/build/src/actions/exchange_refresh_token.d.ts +4 -4
  29. package/build/src/actions/issue_authorization_code.d.ts +2 -2
  30. package/build/src/controllers/authorize_controller.d.ts +11 -11
  31. package/build/src/controllers/metadata_controller.d.ts +7 -7
  32. package/build/src/controllers/register_controller.d.ts +30 -30
  33. package/build/src/guard/guard.d.ts +1 -1
  34. package/build/src/guard/lucid.d.ts +8 -0
  35. package/build/src/guard/lucid.js +46 -0
  36. package/build/src/guard/main.d.ts +2 -9
  37. package/build/src/guard/main.js +2 -6
  38. package/build/src/guard/types.d.ts +0 -9
  39. package/build/src/guard/user_provider.d.ts +9 -1
  40. package/build/src/middleware/any_scope_middleware.js +1 -2
  41. package/build/src/middleware/scope_middleware.js +1 -2
  42. package/build/src/oauth_error.d.ts +74 -74
  43. package/build/src/services/client_service.d.ts +5 -2
  44. package/build/src/sesame_manager.d.ts +6 -5
  45. package/build/src/storage/consent_retry.d.ts +4 -0
  46. package/build/src/storage/drivers/kysely.d.ts +166 -0
  47. package/build/src/storage/drivers/kysely.js +480 -0
  48. package/build/src/storage/drivers/lucid.d.ts +162 -0
  49. package/build/src/storage/drivers/lucid.js +549 -0
  50. package/build/src/storage/migrations/kysely.d.ts +6 -0
  51. package/build/src/storage/types.d.ts +197 -0
  52. package/build/src/storage/types.js +1 -0
  53. package/build/src/stores.d.ts +21 -0
  54. package/build/src/types.d.ts +9 -1
  55. package/build/src/types.js +2 -0
  56. package/build/stubs/config/sesame.stub +4 -1
  57. package/build/stubs/config/sesame_kysely.stub +35 -0
  58. package/build/stubs/migrations/kysely/create_oauth_tables.stub +151 -0
  59. package/build/taze.config.d.ts +2 -0
  60. package/build/{token_controller-DyI7oy-U.js → token_controller-DRatCQNT.js} +74 -63
  61. package/build/types-DEtn2Zdb.js +75 -0
  62. package/build/{userinfo_controller-RLk8cN_o.js → userinfo_controller-YwN26wK-.js} +5 -8
  63. package/build/vite.config.d.ts +1 -1
  64. package/package.json +33 -17
  65. package/build/chunk-DF48asd8.js +0 -9
  66. package/build/oauth_access_token-Cz_5gNBx.js +0 -29
  67. package/build/oauth_client-BSanvSql.js +0 -63
  68. package/build/sesame_manager-B1Jgq1v2.js +0 -6
  69. /package/build/{oauth_error-C7UhDb2q.js → oauth_error-CvxtZvjp.js} +0 -0
  70. /package/build/{token_service-DwnfAR9F.js → token_service-DDQ3Dxaj.js} +0 -0
@@ -0,0 +1,197 @@
1
+ import type { DateTime } from 'luxon';
2
+ /**
3
+ * Stored OAuth client. `clientSecret` is a hash and must never be exposed
4
+ * in public responses.
5
+ */
6
+ export interface OAuthClientRecord {
7
+ id: string;
8
+ clientId: string;
9
+ clientSecret: string | null;
10
+ name: string;
11
+ redirectUris: string[];
12
+ scopes: string[];
13
+ grantTypes: string[];
14
+ isPublic: boolean;
15
+ isDisabled: boolean;
16
+ requirePkce: boolean;
17
+ type: string | null;
18
+ metadata: Record<string, any> | null;
19
+ userId: string | null;
20
+ createdAt: DateTime;
21
+ updatedAt: DateTime;
22
+ }
23
+ export interface OAuthAccessTokenRecord {
24
+ id: string;
25
+ tokenHash: string;
26
+ clientId: string;
27
+ userId: string | null;
28
+ scopes: string[];
29
+ expiresAt: DateTime;
30
+ revokedAt: DateTime | null;
31
+ createdAt: DateTime;
32
+ updatedAt: DateTime;
33
+ }
34
+ export interface OAuthRefreshTokenRecord {
35
+ id: string;
36
+ token: string;
37
+ accessTokenId: string;
38
+ clientId: string;
39
+ userId: string;
40
+ scopes: string[];
41
+ expiresAt: DateTime;
42
+ revokedAt: DateTime | null;
43
+ createdAt: DateTime;
44
+ updatedAt: DateTime;
45
+ }
46
+ export interface OAuthAuthorizationCodeRecord {
47
+ id: string;
48
+ code: string;
49
+ clientId: string;
50
+ userId: string;
51
+ scopes: string[];
52
+ redirectUri: string;
53
+ codeChallenge: string | null;
54
+ codeChallengeMethod: string | null;
55
+ nonce: string | null;
56
+ expiresAt: DateTime;
57
+ createdAt: DateTime;
58
+ updatedAt: DateTime;
59
+ }
60
+ export interface OAuthConsentRecord {
61
+ id: string;
62
+ clientId: string;
63
+ userId: string;
64
+ scopes: string[];
65
+ createdAt: DateTime;
66
+ updatedAt: DateTime;
67
+ }
68
+ export interface OAuthPendingAuthorizationRequestRecord {
69
+ id: string;
70
+ token: string;
71
+ userId: string;
72
+ clientId: string;
73
+ redirectUri: string;
74
+ scopes: string[];
75
+ state: string | null;
76
+ codeChallenge: string | null;
77
+ codeChallengeMethod: string | null;
78
+ nonce: string | null;
79
+ expiresAt: DateTime;
80
+ createdAt: DateTime;
81
+ }
82
+ type SesameOptionalCreateKeys<T> = Extract<keyof T, 'createdAt' | 'updatedAt'> | {
83
+ [K in keyof T]-?: null extends T[K] ? K : never;
84
+ }[keyof T];
85
+ /**
86
+ * Nullable fields default to null; timestamps default to the current time.
87
+ */
88
+ export type SesameCreateRecord<T> = Omit<T, SesameOptionalCreateKeys<T>> & Partial<Pick<T, SesameOptionalCreateKeys<T>>>;
89
+ /**
90
+ * Creation input for each persisted OAuth record.
91
+ */
92
+ export type CreateClientRecord = SesameCreateRecord<OAuthClientRecord>;
93
+ export type CreateAccessTokenRecord = SesameCreateRecord<OAuthAccessTokenRecord>;
94
+ export type CreateRefreshTokenRecord = SesameCreateRecord<OAuthRefreshTokenRecord>;
95
+ export type CreateAuthorizationCodeRecord = SesameCreateRecord<OAuthAuthorizationCodeRecord>;
96
+ export type CreatePendingAuthorizationRequestRecord = SesameCreateRecord<OAuthPendingAuthorizationRequestRecord>;
97
+ export type UpdateClientRecord = Partial<Pick<OAuthClientRecord, 'name' | 'redirectUris' | 'scopes' | 'grantTypes' | 'isDisabled' | 'requirePkce' | 'metadata'>>;
98
+ export interface SesamePurgeResult {
99
+ accessTokens: number;
100
+ refreshTokens: number;
101
+ authorizationCodes: number;
102
+ pendingRequests: number;
103
+ }
104
+ export interface IssueTokenPairOptions {
105
+ accessToken: CreateAccessTokenRecord;
106
+ refreshToken: CreateRefreshTokenRecord;
107
+ }
108
+ export interface ExchangeAuthorizationCodeOptions {
109
+ codeId: string;
110
+ accessToken: CreateAccessTokenRecord;
111
+ refreshToken: CreateRefreshTokenRecord | null;
112
+ }
113
+ export interface RotateRefreshTokenOptions extends IssueTokenPairOptions {
114
+ oldRefreshTokenId: string;
115
+ oldAccessTokenId: string;
116
+ revokedAt: DateTime;
117
+ }
118
+ export interface PurgeTokensOptions {
119
+ purgeRevoked: boolean;
120
+ purgeExpired: boolean;
121
+ cutoff: DateTime;
122
+ now: DateTime;
123
+ }
124
+ /**
125
+ * OAuth-specific persistence operations. Callers never build database predicates.
126
+ * Conditional exchanges and rotations return false when another request won.
127
+ */
128
+ export interface SesameStore {
129
+ findClient(clientId: string): Promise<OAuthClientRecord | null>;
130
+ listClients(options?: {
131
+ userId?: string;
132
+ }): Promise<OAuthClientRecord[]>;
133
+ createClient(data: CreateClientRecord): Promise<OAuthClientRecord>;
134
+ updateClient(options: {
135
+ id: string;
136
+ data: UpdateClientRecord;
137
+ }): Promise<void>;
138
+ updateClientSecret(options: {
139
+ id: string;
140
+ secret: string;
141
+ }): Promise<void>;
142
+ deleteClient(clientId: string): Promise<boolean>;
143
+ findAccessToken(options: {
144
+ hash: string;
145
+ clientId?: string;
146
+ }): Promise<OAuthAccessTokenRecord | null>;
147
+ createAccessToken(data: CreateAccessTokenRecord): Promise<void>;
148
+ revokeAccessToken(options: {
149
+ hash: string;
150
+ clientId: string;
151
+ now: DateTime;
152
+ }): Promise<boolean>;
153
+ findRefreshToken(options: {
154
+ hash: string;
155
+ clientId: string;
156
+ }): Promise<OAuthRefreshTokenRecord | null>;
157
+ revokeRefreshToken(options: {
158
+ hash: string;
159
+ clientId: string;
160
+ now: DateTime;
161
+ }): Promise<void>;
162
+ revokeTokenFamily(options: {
163
+ clientId: string;
164
+ userId: string;
165
+ now: DateTime;
166
+ }): Promise<void>;
167
+ findAuthorizationCode(options: {
168
+ code: string;
169
+ clientId: string;
170
+ }): Promise<OAuthAuthorizationCodeRecord | null>;
171
+ createAuthorizationCode(data: CreateAuthorizationCodeRecord): Promise<void>;
172
+ deleteAuthorizationCode(id: string): Promise<void>;
173
+ exchangeAuthorizationCode(options: ExchangeAuthorizationCodeOptions): Promise<boolean>;
174
+ findConsent(options: {
175
+ clientId: string;
176
+ userId: string;
177
+ }): Promise<OAuthConsentRecord | null>;
178
+ grantConsent(options: {
179
+ clientId: string;
180
+ userId: string;
181
+ scopes: string[];
182
+ }): Promise<void>;
183
+ createPendingAuthorizationRequest(data: CreatePendingAuthorizationRequestRecord): Promise<void>;
184
+ consumePendingAuthorizationRequest(options: {
185
+ token: string;
186
+ userId: string;
187
+ now: DateTime;
188
+ }): Promise<OAuthPendingAuthorizationRequestRecord | null>;
189
+ issueTokenPair(options: IssueTokenPairOptions): Promise<void>;
190
+ rotateRefreshToken(options: RotateRefreshTokenOptions): Promise<boolean>;
191
+ revokeAllForUser(options: {
192
+ userId: string;
193
+ now: DateTime;
194
+ }): Promise<void>;
195
+ purgeTokens(options: PurgeTokensOptions): Promise<SesamePurgeResult>;
196
+ }
197
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,21 @@
1
+ import type { ApplicationService, ConfigProvider } from '@adonisjs/core/types';
2
+ import type { Kysely } from 'kysely';
3
+ import type { SesameStore } from './storage/types.ts';
4
+ import type { KyselyDialect } from './storage/drivers/kysely.ts';
5
+ export interface KyselyStoreConfig<DB> {
6
+ connection: Kysely<DB> | ((app: ApplicationService) => Kysely<DB> | Promise<Kysely<DB>>);
7
+ dialect?: KyselyDialect;
8
+ }
9
+ /**
10
+ * Store driver factories resolved by the AdonisJS service provider.
11
+ */
12
+ export declare const stores: {
13
+ /**
14
+ * Use the application's Lucid connection for OAuth persistence.
15
+ */
16
+ lucid(): ConfigProvider<SesameStore>;
17
+ /**
18
+ * Use an existing Kysely connection for OAuth persistence.
19
+ */
20
+ kysely<DB>(options: KyselyStoreConfig<DB>): ConfigProvider<SesameStore>;
21
+ };
@@ -1,6 +1,9 @@
1
1
  import type { HttpContext } from '@adonisjs/core/http';
2
+ import type { ConfigProvider } from '@adonisjs/core/types';
2
3
  import type { JWK } from 'jose';
3
4
  import type { OAuthUserProviderContract } from './guard/types.ts';
5
+ import type { OAuthClientRecord, SesameStore } from './storage/types.ts';
6
+ export type * from './storage/types.ts';
4
7
  /**
5
8
  * Augment this interface via module augmentation to enable
6
9
  * type-safe scope names across the application.
@@ -131,7 +134,7 @@ export interface UpdateClientOptions {
131
134
  * Includes the raw secret (only available at creation time).
132
135
  */
133
136
  export interface CreateClientResult {
134
- client: import('./models/oauth_client.ts').OAuthClient;
137
+ client: OAuthClientRecord;
135
138
  clientSecret: string | null;
136
139
  }
137
140
  /**
@@ -142,6 +145,10 @@ export interface CreateClientResult {
142
145
  * page redirects for the authorization flow.
143
146
  */
144
147
  export interface SesameConfig {
148
+ /**
149
+ * Store driver resolved by the service provider.
150
+ */
151
+ store: ConfigProvider<SesameStore>;
145
152
  /**
146
153
  * The issuer URL (must be HTTPS in production).
147
154
  * Used in JWT `iss` claim and discovery metadata.
@@ -256,6 +263,7 @@ export interface SesameConfig {
256
263
  * Created by `defineConfig()` from user-supplied `SesameConfig`.
257
264
  */
258
265
  export interface ResolvedSesameConfig {
266
+ store: ConfigProvider<SesameStore>;
259
267
  issuer: string;
260
268
  scopes: Record<string, string>;
261
269
  defaultScopes: string[];
@@ -0,0 +1,2 @@
1
+ import { i as collectOidcClaims, n as OIDC_SCOPES, r as RESERVED_OIDC_CLAIMS, t as BUILTIN_SCOPES } from "../types-DEtn2Zdb.js";
2
+ export { BUILTIN_SCOPES, OIDC_SCOPES, RESERVED_OIDC_CLAIMS, collectOidcClaims };
@@ -1,12 +1,15 @@
1
1
  {{{
2
- exports: { defineConfig: 'import { defineConfig } from \'@julr/sesame\'' }
2
+ exports({ to: app.configPath('sesame.ts') })
3
3
  }}}
4
4
  import env from '#start/env'
5
+ import { defineConfig, stores } from '@julr/sesame'
5
6
  import type { InferScopes } from '@julr/sesame/types'
6
7
 
7
8
  const sesameConfig = defineConfig({
8
9
  issuer: env.get('APP_URL'),
9
10
 
11
+ store: stores.lucid(),
12
+
10
13
  scopes: {
11
14
  // Define your available scopes here
12
15
  // 'read': 'Read access',
@@ -0,0 +1,35 @@
1
+ {{{
2
+ exports({ to: app.configPath('sesame.ts') })
3
+ }}}
4
+ import env from '#start/env'
5
+ import { defineConfig, stores } from '@julr/sesame'
6
+ import type { InferScopes } from '@julr/sesame/types'
7
+
8
+ const sesameConfig = defineConfig({
9
+ issuer: env.get('APP_URL'),
10
+
11
+ // Replace this import with your application's Kysely instance.
12
+ store: stores.kysely({
13
+ connection: async () => {
14
+ const { db } = await import('#services/kysely')
15
+ return db
16
+ },
17
+ }),
18
+
19
+ scopes: {},
20
+ defaultScopes: [],
21
+ grantTypes: ['authorization_code', 'refresh_token'],
22
+ accessTokenTtl: '1h',
23
+ refreshTokenTtl: '30d',
24
+ authorizationCodeTtl: '10m',
25
+ loginPage: '/login',
26
+ consentPage: '/oauth/consent',
27
+ allowDynamicRegistration: false,
28
+ allowPublicRegistration: false,
29
+ })
30
+
31
+ export default sesameConfig
32
+
33
+ declare module '@julr/sesame/types' {
34
+ interface SesameScopes extends InferScopes<typeof sesameConfig> {}
35
+ }
@@ -0,0 +1,151 @@
1
+ {{{
2
+ exports({
3
+ to: app.makePath('database/kysely_migrations/create_oauth_tables.ts')
4
+ })
5
+ }}}
6
+
7
+ import type { Kysely } from 'kysely'
8
+
9
+ /**
10
+ * Kysely migration for Sesame's OAuth tables.
11
+ */
12
+ export async function up(db: Kysely<any>): Promise<void> {
13
+ // Clients own OAuth grants and define the allowed redirects, scopes, and grant types.
14
+ await db.schema
15
+ .createTable('oauth_clients')
16
+ .addColumn('id', 'varchar(36)', (column) => column.primaryKey())
17
+ .addColumn('client_id', 'varchar(255)', (column) => column.notNull().unique())
18
+ .addColumn('client_secret', 'text')
19
+ .addColumn('name', 'varchar(255)', (column) => column.notNull())
20
+ .addColumn('redirect_uris', 'json', (column) => column.notNull())
21
+ .addColumn('scopes', 'json', (column) => column.notNull())
22
+ .addColumn('grant_types', 'json', (column) => column.notNull())
23
+ .addColumn('is_public', 'boolean', (column) => column.notNull().defaultTo(false))
24
+ .addColumn('is_disabled', 'boolean', (column) => column.notNull().defaultTo(false))
25
+ .addColumn('require_pkce', 'boolean', (column) => column.notNull().defaultTo(true))
26
+ .addColumn('type', 'varchar(255)')
27
+ .addColumn('metadata', 'json')
28
+ .addColumn('user_id', 'varchar(255)')
29
+ .addColumn('created_at', 'timestamp', (column) => column.notNull())
30
+ .addColumn('updated_at', 'timestamp', (column) => column.notNull())
31
+ .execute()
32
+
33
+ // Access tokens are stored by hash so a leaked database never exposes bearer tokens.
34
+ await db.schema
35
+ .createTable('oauth_access_tokens')
36
+ .addColumn('id', 'varchar(36)', (column) => column.primaryKey())
37
+ .addColumn('token_hash', 'varchar(255)', (column) => column.notNull().unique())
38
+ .addColumn('client_id', 'varchar(255)', (column) =>
39
+ column.notNull().references('oauth_clients.client_id').onDelete('cascade')
40
+ )
41
+ .addColumn('user_id', 'varchar(255)')
42
+ .addColumn('scopes', 'json', (column) => column.notNull())
43
+ .addColumn('expires_at', 'timestamp', (column) => column.notNull())
44
+ .addColumn('revoked_at', 'timestamp')
45
+ .addColumn('created_at', 'timestamp', (column) => column.notNull())
46
+ .addColumn('updated_at', 'timestamp', (column) => column.notNull())
47
+ .execute()
48
+
49
+ // Refresh tokens point to their access token so rotation can revoke the old pair.
50
+ await db.schema
51
+ .createTable('oauth_refresh_tokens')
52
+ .addColumn('id', 'varchar(36)', (column) => column.primaryKey())
53
+ .addColumn('token', 'varchar(255)', (column) => column.notNull())
54
+ .addColumn('access_token_id', 'varchar(36)', (column) => column.notNull())
55
+ .addColumn('client_id', 'varchar(255)', (column) =>
56
+ column.notNull().references('oauth_clients.client_id').onDelete('cascade')
57
+ )
58
+ .addColumn('user_id', 'varchar(255)', (column) => column.notNull())
59
+ .addColumn('scopes', 'json', (column) => column.notNull())
60
+ .addColumn('expires_at', 'timestamp', (column) => column.notNull())
61
+ .addColumn('revoked_at', 'timestamp')
62
+ .addColumn('created_at', 'timestamp', (column) => column.notNull())
63
+ .addColumn('updated_at', 'timestamp', (column) => column.notNull())
64
+ .execute()
65
+ // Token lookup is part of the refresh grant's hot path.
66
+ await db.schema
67
+ .createIndex('oauth_refresh_tokens_token_idx')
68
+ .on('oauth_refresh_tokens')
69
+ .column('token')
70
+ .execute()
71
+
72
+ // Authorization codes are short-lived, single-use credentials for the code grant.
73
+ await db.schema
74
+ .createTable('oauth_authorization_codes')
75
+ .addColumn('id', 'varchar(36)', (column) => column.primaryKey())
76
+ .addColumn('code', 'varchar(255)', (column) => column.notNull())
77
+ .addColumn('client_id', 'varchar(255)', (column) =>
78
+ column.notNull().references('oauth_clients.client_id').onDelete('cascade')
79
+ )
80
+ .addColumn('user_id', 'varchar(255)', (column) => column.notNull())
81
+ .addColumn('scopes', 'json', (column) => column.notNull())
82
+ .addColumn('redirect_uri', 'text', (column) => column.notNull())
83
+ .addColumn('code_challenge', 'varchar(255)')
84
+ .addColumn('code_challenge_method', 'varchar(255)')
85
+ .addColumn('nonce', 'varchar(255)')
86
+ .addColumn('expires_at', 'timestamp', (column) => column.notNull())
87
+ .addColumn('created_at', 'timestamp', (column) => column.notNull())
88
+ .addColumn('updated_at', 'timestamp', (column) => column.notNull())
89
+ .execute()
90
+ // Locate the authorization code submitted to the token endpoint.
91
+ await db.schema
92
+ .createIndex('oauth_authorization_codes_code_idx')
93
+ .on('oauth_authorization_codes')
94
+ .column('code')
95
+ .execute()
96
+
97
+ // A consent records the scopes approved by one user for one client.
98
+ await db.schema
99
+ .createTable('oauth_consents')
100
+ .addColumn('id', 'varchar(36)', (column) => column.primaryKey())
101
+ .addColumn('client_id', 'varchar(255)', (column) =>
102
+ column.notNull().references('oauth_clients.client_id').onDelete('cascade')
103
+ )
104
+ .addColumn('user_id', 'varchar(255)', (column) => column.notNull())
105
+ .addColumn('scopes', 'json', (column) => column.notNull())
106
+ .addColumn('created_at', 'timestamp', (column) => column.notNull())
107
+ .addColumn('updated_at', 'timestamp', (column) => column.notNull())
108
+ .execute()
109
+ // Only one consent record may exist for a client and user pair.
110
+ await db.schema
111
+ .createIndex('oauth_consents_client_id_user_id_unique')
112
+ .on('oauth_consents')
113
+ .columns(['client_id', 'user_id'])
114
+ .unique()
115
+ .execute()
116
+
117
+ // Pending requests carry the authorization context across the consent redirect.
118
+ await db.schema
119
+ .createTable('oauth_pending_authorization_requests')
120
+ .addColumn('id', 'varchar(36)', (column) => column.primaryKey())
121
+ .addColumn('token', 'varchar(255)', (column) => column.notNull())
122
+ .addColumn('client_id', 'varchar(255)', (column) =>
123
+ column.notNull().references('oauth_clients.client_id').onDelete('cascade')
124
+ )
125
+ .addColumn('user_id', 'varchar(255)', (column) => column.notNull())
126
+ .addColumn('scopes', 'json', (column) => column.notNull())
127
+ .addColumn('redirect_uri', 'text', (column) => column.notNull())
128
+ .addColumn('state', 'varchar(255)')
129
+ .addColumn('code_challenge', 'varchar(255)')
130
+ .addColumn('code_challenge_method', 'varchar(255)')
131
+ .addColumn('nonce', 'varchar(255)')
132
+ .addColumn('expires_at', 'timestamp', (column) => column.notNull())
133
+ .addColumn('created_at', 'timestamp', (column) => column.notNull())
134
+ .execute()
135
+ // Resolve the opaque pending-request token when the consent form returns.
136
+ await db.schema
137
+ .createIndex('oauth_pending_authorization_requests_token_idx')
138
+ .on('oauth_pending_authorization_requests')
139
+ .column('token')
140
+ .execute()
141
+ }
142
+
143
+ export async function down(db: Kysely<any>): Promise<void> {
144
+ // Drop children before clients to respect the client foreign keys.
145
+ await db.schema.dropTable('oauth_pending_authorization_requests').execute()
146
+ await db.schema.dropTable('oauth_consents').execute()
147
+ await db.schema.dropTable('oauth_authorization_codes').execute()
148
+ await db.schema.dropTable('oauth_refresh_tokens').execute()
149
+ await db.schema.dropTable('oauth_access_tokens').execute()
150
+ await db.schema.dropTable('oauth_clients').execute()
151
+ }
@@ -0,0 +1,2 @@
1
+ declare const _default: Partial<import("taze").CheckOptions>;
2
+ export default _default;