@ttoss/auth-postgresdb 0.1.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 +21 -0
- package/README.md +76 -0
- package/dist/index.cjs +507 -0
- package/dist/index.d.cts +244 -0
- package/dist/index.d.mts +244 -0
- package/dist/index.mjs +475 -0
- package/package.json +54 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
/** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
|
|
2
|
+
import { hashAuthorizationCode } from "@ttoss/auth-core";
|
|
3
|
+
import { Column, DataType, Model, PrimaryKey, Table } from "@ttoss/postgresdb";
|
|
4
|
+
|
|
5
|
+
//#region src/stores/createAuthCodeStore.ts
|
|
6
|
+
/**
|
|
7
|
+
* Creates an {@link AuthCodeStore} backed by the `oauth_auth_codes` table,
|
|
8
|
+
* storing codes by SHA-256 hash.
|
|
9
|
+
*
|
|
10
|
+
* The engine hands the store the plaintext code on every call and never compares
|
|
11
|
+
* the returned `code` against anything — it reads only `clientId`,
|
|
12
|
+
* `redirectUri`, `codeChallenge`, `scopes`, `subject`, and `expiresAt`. So the
|
|
13
|
+
* adapter hashes to find the row and echoes the presented value back, and a
|
|
14
|
+
* database dump yields no replayable codes.
|
|
15
|
+
*/
|
|
16
|
+
var createAuthCodeStore = ({
|
|
17
|
+
model
|
|
18
|
+
}) => {
|
|
19
|
+
return {
|
|
20
|
+
save: async code => {
|
|
21
|
+
await model.upsert({
|
|
22
|
+
codeHash: hashAuthorizationCode({
|
|
23
|
+
code: code.code
|
|
24
|
+
}),
|
|
25
|
+
clientId: code.clientId,
|
|
26
|
+
redirectUri: code.redirectUri,
|
|
27
|
+
codeChallenge: code.codeChallenge,
|
|
28
|
+
scopes: code.scopes,
|
|
29
|
+
subject: code.subject,
|
|
30
|
+
expiresAt: new Date(code.expiresAt)
|
|
31
|
+
});
|
|
32
|
+
},
|
|
33
|
+
get: async code => {
|
|
34
|
+
const row = await model.findByPk(hashAuthorizationCode({
|
|
35
|
+
code
|
|
36
|
+
}));
|
|
37
|
+
if (!row) return;
|
|
38
|
+
return {
|
|
39
|
+
code,
|
|
40
|
+
clientId: row.clientId,
|
|
41
|
+
redirectUri: row.redirectUri,
|
|
42
|
+
codeChallenge: row.codeChallenge,
|
|
43
|
+
scopes: row.scopes,
|
|
44
|
+
subject: row.subject,
|
|
45
|
+
expiresAt: row.expiresAt.getTime()
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
delete: async code => {
|
|
49
|
+
await model.destroy({
|
|
50
|
+
where: {
|
|
51
|
+
codeHash: hashAuthorizationCode({
|
|
52
|
+
code
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/stores/createClientStore.ts
|
|
62
|
+
/**
|
|
63
|
+
* Registration fields that have their own column. Everything else a client
|
|
64
|
+
* submits goes to `metadata`, so the document round-trips unchanged.
|
|
65
|
+
*/
|
|
66
|
+
var COLUMN_FIELDS = ["client_id", "client_secret", "client_name", "redirect_uris", "grant_types", "response_types", "token_endpoint_auth_method", "scope", "client_id_issued_at"];
|
|
67
|
+
var toRecord = row => {
|
|
68
|
+
return {
|
|
69
|
+
...row.metadata,
|
|
70
|
+
client_id: row.clientId,
|
|
71
|
+
redirect_uris: row.redirectUris,
|
|
72
|
+
...(row.clientSecret !== null && {
|
|
73
|
+
client_secret: row.clientSecret
|
|
74
|
+
}),
|
|
75
|
+
...(row.clientName !== null && {
|
|
76
|
+
client_name: row.clientName
|
|
77
|
+
}),
|
|
78
|
+
...(row.grantTypes !== null && {
|
|
79
|
+
grant_types: row.grantTypes
|
|
80
|
+
}),
|
|
81
|
+
...(row.responseTypes !== null && {
|
|
82
|
+
response_types: row.responseTypes
|
|
83
|
+
}),
|
|
84
|
+
...(row.tokenEndpointAuthMethod !== null && {
|
|
85
|
+
token_endpoint_auth_method: row.tokenEndpointAuthMethod
|
|
86
|
+
}),
|
|
87
|
+
...(row.scope !== null && {
|
|
88
|
+
scope: row.scope
|
|
89
|
+
}),
|
|
90
|
+
...(row.clientIdIssuedAt !== null && {
|
|
91
|
+
client_id_issued_at: Number(row.clientIdIssuedAt)
|
|
92
|
+
})
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
var toMetadata = client => {
|
|
96
|
+
const metadata = {};
|
|
97
|
+
for (const [key, value] of Object.entries(client)) if (!COLUMN_FIELDS.includes(key)) metadata[key] = value;
|
|
98
|
+
return metadata;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Creates a {@link ClientStore} backed by the `oauth_clients` table.
|
|
102
|
+
*
|
|
103
|
+
* `register` upserts, so re-registering an existing `client_id` replaces the
|
|
104
|
+
* stored document rather than failing on the primary key.
|
|
105
|
+
*/
|
|
106
|
+
var createClientStore = ({
|
|
107
|
+
model
|
|
108
|
+
}) => {
|
|
109
|
+
return {
|
|
110
|
+
get: async clientId => {
|
|
111
|
+
const row = await model.findByPk(clientId);
|
|
112
|
+
return row ? toRecord(row) : void 0;
|
|
113
|
+
},
|
|
114
|
+
register: async client => {
|
|
115
|
+
await model.upsert({
|
|
116
|
+
clientId: client.client_id,
|
|
117
|
+
clientSecret: client.client_secret ?? null,
|
|
118
|
+
clientName: client.client_name ?? null,
|
|
119
|
+
redirectUris: client.redirect_uris,
|
|
120
|
+
grantTypes: client.grant_types ?? null,
|
|
121
|
+
responseTypes: client.response_types ?? null,
|
|
122
|
+
tokenEndpointAuthMethod: client.token_endpoint_auth_method ?? null,
|
|
123
|
+
scope: client.scope ?? null,
|
|
124
|
+
clientIdIssuedAt: client.client_id_issued_at ?? null,
|
|
125
|
+
metadata: toMetadata(client)
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region src/stores/createConsentStore.ts
|
|
133
|
+
/**
|
|
134
|
+
* Creates a consent store backed by the `oauth_consents` table, for use with
|
|
135
|
+
* `createRedirectConsentOnAuthorize`.
|
|
136
|
+
*
|
|
137
|
+
* Reads and deletes satisfy `ConsentGrantStore`; `saveConsentGrant` covers the
|
|
138
|
+
* write the consent page performs. Grants are single-use — the `onAuthorize`
|
|
139
|
+
* hook deletes each one as it consumes it.
|
|
140
|
+
*/
|
|
141
|
+
var createConsentStore = ({
|
|
142
|
+
model
|
|
143
|
+
}) => {
|
|
144
|
+
return {
|
|
145
|
+
saveConsentGrant: async ({
|
|
146
|
+
codeChallenge,
|
|
147
|
+
subject,
|
|
148
|
+
scopes,
|
|
149
|
+
expiresAt
|
|
150
|
+
}) => {
|
|
151
|
+
await model.upsert({
|
|
152
|
+
codeChallenge,
|
|
153
|
+
subject,
|
|
154
|
+
scopes,
|
|
155
|
+
expiresAt: new Date(expiresAt)
|
|
156
|
+
});
|
|
157
|
+
},
|
|
158
|
+
getConsentGrant: async ({
|
|
159
|
+
codeChallenge
|
|
160
|
+
}) => {
|
|
161
|
+
const row = await model.findByPk(codeChallenge);
|
|
162
|
+
if (!row) return;
|
|
163
|
+
return {
|
|
164
|
+
subject: row.subject,
|
|
165
|
+
scopes: row.scopes,
|
|
166
|
+
expiresAt: row.expiresAt.getTime()
|
|
167
|
+
};
|
|
168
|
+
},
|
|
169
|
+
deleteConsentGrant: async ({
|
|
170
|
+
codeChallenge
|
|
171
|
+
}) => {
|
|
172
|
+
await model.destroy({
|
|
173
|
+
where: {
|
|
174
|
+
codeChallenge
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
//#endregion
|
|
182
|
+
//#region src/stores/createRefreshTokenStore.ts
|
|
183
|
+
/**
|
|
184
|
+
* Creates a {@link RefreshTokenStore} backed by the `oauth_refresh_tokens`
|
|
185
|
+
* table, keyed by token hash and by the `(clientId, subject)` owner that
|
|
186
|
+
* `deleteByOwner` revokes on reuse detection.
|
|
187
|
+
*/
|
|
188
|
+
var createRefreshTokenStore = ({
|
|
189
|
+
model
|
|
190
|
+
}) => {
|
|
191
|
+
return {
|
|
192
|
+
save: async token => {
|
|
193
|
+
await model.upsert({
|
|
194
|
+
tokenHash: token.tokenHash,
|
|
195
|
+
clientId: token.clientId,
|
|
196
|
+
subject: token.subject,
|
|
197
|
+
scopes: token.scopes,
|
|
198
|
+
expiresAt: new Date(token.expiresAt),
|
|
199
|
+
consumedAt: token.consumedAt === void 0 ? null : new Date(token.consumedAt)
|
|
200
|
+
});
|
|
201
|
+
},
|
|
202
|
+
get: async tokenHash => {
|
|
203
|
+
const row = await model.findByPk(tokenHash);
|
|
204
|
+
if (!row) return;
|
|
205
|
+
return {
|
|
206
|
+
tokenHash: row.tokenHash,
|
|
207
|
+
clientId: row.clientId,
|
|
208
|
+
subject: row.subject,
|
|
209
|
+
scopes: row.scopes,
|
|
210
|
+
expiresAt: row.expiresAt.getTime(),
|
|
211
|
+
/**
|
|
212
|
+
* The key is omitted, not set to `null`. Rotation tests
|
|
213
|
+
* `stored.consumedAt !== undefined` to detect reuse, and a nullable
|
|
214
|
+
* timestamp column reads back as `null` — which would make every live
|
|
215
|
+
* token look consumed, so the first refresh would be treated as a
|
|
216
|
+
* replay and revoke the owner's entire token set.
|
|
217
|
+
*/
|
|
218
|
+
...(row.consumedAt !== null && {
|
|
219
|
+
consumedAt: row.consumedAt.getTime()
|
|
220
|
+
})
|
|
221
|
+
};
|
|
222
|
+
},
|
|
223
|
+
delete: async tokenHash => {
|
|
224
|
+
await model.destroy({
|
|
225
|
+
where: {
|
|
226
|
+
tokenHash
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
},
|
|
230
|
+
deleteByOwner: async ({
|
|
231
|
+
clientId,
|
|
232
|
+
subject
|
|
233
|
+
}) => {
|
|
234
|
+
await model.destroy({
|
|
235
|
+
where: {
|
|
236
|
+
clientId,
|
|
237
|
+
subject
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
//#endregion
|
|
245
|
+
//#region src/createPostgresdbOAuthStores.ts
|
|
246
|
+
/**
|
|
247
|
+
* Creates every durable OAuth store from a `@ttoss/postgresdb` `db` handle.
|
|
248
|
+
*
|
|
249
|
+
* The stores are mechanical adapters between the `@ttoss/auth-core` store
|
|
250
|
+
* contracts and Sequelize, so an app that already uses `@ttoss/postgresdb` does
|
|
251
|
+
* not have to write them — nor reach around its own ORM to inject a raw `pg`
|
|
252
|
+
* query runner.
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* ```typescript
|
|
256
|
+
* import { createPostgresdbOAuthStores, oauthModels } from '@ttoss/auth-postgresdb';
|
|
257
|
+
* import { initialize } from '@ttoss/postgresdb';
|
|
258
|
+
*
|
|
259
|
+
* const db = await initialize({ models: { ...oauthModels, User } });
|
|
260
|
+
*
|
|
261
|
+
* const { clientStore, authCodeStore, consentStore, refreshTokenStore } =
|
|
262
|
+
* createPostgresdbOAuthStores({ db });
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
265
|
+
var createPostgresdbOAuthStores = ({
|
|
266
|
+
db
|
|
267
|
+
}) => {
|
|
268
|
+
return {
|
|
269
|
+
clientStore: createClientStore({
|
|
270
|
+
model: db.OAuthClient
|
|
271
|
+
}),
|
|
272
|
+
authCodeStore: createAuthCodeStore({
|
|
273
|
+
model: db.OAuthAuthCode
|
|
274
|
+
}),
|
|
275
|
+
consentStore: createConsentStore({
|
|
276
|
+
model: db.OAuthConsent
|
|
277
|
+
}),
|
|
278
|
+
refreshTokenStore: createRefreshTokenStore({
|
|
279
|
+
model: db.OAuthRefreshToken
|
|
280
|
+
})
|
|
281
|
+
};
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
//#endregion
|
|
285
|
+
//#region \0@oxc-project+runtime@0.134.0/helpers/esm/decorateMetadata.js
|
|
286
|
+
function __decorateMetadata(k, v) {
|
|
287
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
//#endregion
|
|
291
|
+
//#region \0@oxc-project+runtime@0.134.0/helpers/esm/decorate.js
|
|
292
|
+
function __decorate(decorators, target, key, desc) {
|
|
293
|
+
var c = arguments.length,
|
|
294
|
+
r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc,
|
|
295
|
+
d;
|
|
296
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);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;
|
|
297
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
//#endregion
|
|
301
|
+
//#region src/models/OAuthAuthCode.ts
|
|
302
|
+
var OAuthAuthCode = class OAuthAuthCode extends Model {};
|
|
303
|
+
__decorate([PrimaryKey, Column({
|
|
304
|
+
type: DataType.STRING,
|
|
305
|
+
allowNull: false
|
|
306
|
+
}), __decorateMetadata("design:type", String)], OAuthAuthCode.prototype, "codeHash", void 0);
|
|
307
|
+
__decorate([Column({
|
|
308
|
+
type: DataType.STRING,
|
|
309
|
+
allowNull: false
|
|
310
|
+
}), __decorateMetadata("design:type", String)], OAuthAuthCode.prototype, "clientId", void 0);
|
|
311
|
+
__decorate([Column({
|
|
312
|
+
type: DataType.TEXT,
|
|
313
|
+
allowNull: false
|
|
314
|
+
}), __decorateMetadata("design:type", String)], OAuthAuthCode.prototype, "redirectUri", void 0);
|
|
315
|
+
__decorate([Column({
|
|
316
|
+
type: DataType.STRING,
|
|
317
|
+
allowNull: false
|
|
318
|
+
}), __decorateMetadata("design:type", String)], OAuthAuthCode.prototype, "codeChallenge", void 0);
|
|
319
|
+
__decorate([Column({
|
|
320
|
+
type: DataType.JSONB,
|
|
321
|
+
allowNull: false
|
|
322
|
+
}), __decorateMetadata("design:type", Array)], OAuthAuthCode.prototype, "scopes", void 0);
|
|
323
|
+
__decorate([Column({
|
|
324
|
+
type: DataType.STRING,
|
|
325
|
+
allowNull: false
|
|
326
|
+
}), __decorateMetadata("design:type", String)], OAuthAuthCode.prototype, "subject", void 0);
|
|
327
|
+
__decorate([Column({
|
|
328
|
+
type: DataType.DATE,
|
|
329
|
+
allowNull: false
|
|
330
|
+
}), __decorateMetadata("design:type", typeof Date === "undefined" ? Object : Date)], OAuthAuthCode.prototype, "expiresAt", void 0);
|
|
331
|
+
OAuthAuthCode = __decorate([Table({
|
|
332
|
+
tableName: "oauth_auth_codes",
|
|
333
|
+
modelName: "oauthAuthCode",
|
|
334
|
+
indexes: [{
|
|
335
|
+
fields: ["expires_at"]
|
|
336
|
+
}]
|
|
337
|
+
})], OAuthAuthCode);
|
|
338
|
+
|
|
339
|
+
//#endregion
|
|
340
|
+
//#region src/models/OAuthClient.ts
|
|
341
|
+
var OAuthClient = class OAuthClient extends Model {};
|
|
342
|
+
__decorate([PrimaryKey, Column({
|
|
343
|
+
type: DataType.STRING,
|
|
344
|
+
allowNull: false
|
|
345
|
+
}), __decorateMetadata("design:type", String)], OAuthClient.prototype, "clientId", void 0);
|
|
346
|
+
__decorate([Column({
|
|
347
|
+
type: DataType.STRING,
|
|
348
|
+
allowNull: true
|
|
349
|
+
}), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "clientSecret", void 0);
|
|
350
|
+
__decorate([Column({
|
|
351
|
+
type: DataType.STRING,
|
|
352
|
+
allowNull: true
|
|
353
|
+
}), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "clientName", void 0);
|
|
354
|
+
__decorate([Column({
|
|
355
|
+
type: DataType.JSONB,
|
|
356
|
+
allowNull: false
|
|
357
|
+
}), __decorateMetadata("design:type", Array)], OAuthClient.prototype, "redirectUris", void 0);
|
|
358
|
+
__decorate([Column({
|
|
359
|
+
type: DataType.JSONB,
|
|
360
|
+
allowNull: true
|
|
361
|
+
}), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "grantTypes", void 0);
|
|
362
|
+
__decorate([Column({
|
|
363
|
+
type: DataType.JSONB,
|
|
364
|
+
allowNull: true
|
|
365
|
+
}), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "responseTypes", void 0);
|
|
366
|
+
__decorate([Column({
|
|
367
|
+
type: DataType.STRING,
|
|
368
|
+
allowNull: true
|
|
369
|
+
}), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "tokenEndpointAuthMethod", void 0);
|
|
370
|
+
__decorate([Column({
|
|
371
|
+
type: DataType.STRING,
|
|
372
|
+
allowNull: true
|
|
373
|
+
}), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "scope", void 0);
|
|
374
|
+
__decorate([Column({
|
|
375
|
+
type: DataType.BIGINT,
|
|
376
|
+
allowNull: true
|
|
377
|
+
}), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "clientIdIssuedAt", void 0);
|
|
378
|
+
__decorate([Column({
|
|
379
|
+
type: DataType.JSONB,
|
|
380
|
+
allowNull: false,
|
|
381
|
+
defaultValue: {}
|
|
382
|
+
}), __decorateMetadata("design:type", typeof Record === "undefined" ? Object : Record)], OAuthClient.prototype, "metadata", void 0);
|
|
383
|
+
OAuthClient = __decorate([Table({
|
|
384
|
+
tableName: "oauth_clients",
|
|
385
|
+
modelName: "oauthClient"
|
|
386
|
+
})], OAuthClient);
|
|
387
|
+
|
|
388
|
+
//#endregion
|
|
389
|
+
//#region src/models/OAuthConsent.ts
|
|
390
|
+
var OAuthConsent = class OAuthConsent extends Model {};
|
|
391
|
+
__decorate([PrimaryKey, Column({
|
|
392
|
+
type: DataType.STRING,
|
|
393
|
+
allowNull: false
|
|
394
|
+
}), __decorateMetadata("design:type", String)], OAuthConsent.prototype, "codeChallenge", void 0);
|
|
395
|
+
__decorate([Column({
|
|
396
|
+
type: DataType.STRING,
|
|
397
|
+
allowNull: false
|
|
398
|
+
}), __decorateMetadata("design:type", String)], OAuthConsent.prototype, "subject", void 0);
|
|
399
|
+
__decorate([Column({
|
|
400
|
+
type: DataType.JSONB,
|
|
401
|
+
allowNull: false
|
|
402
|
+
}), __decorateMetadata("design:type", Array)], OAuthConsent.prototype, "scopes", void 0);
|
|
403
|
+
__decorate([Column({
|
|
404
|
+
type: DataType.DATE,
|
|
405
|
+
allowNull: false
|
|
406
|
+
}), __decorateMetadata("design:type", typeof Date === "undefined" ? Object : Date)], OAuthConsent.prototype, "expiresAt", void 0);
|
|
407
|
+
OAuthConsent = __decorate([Table({
|
|
408
|
+
tableName: "oauth_consents",
|
|
409
|
+
modelName: "oauthConsent",
|
|
410
|
+
indexes: [{
|
|
411
|
+
fields: ["expires_at"]
|
|
412
|
+
}]
|
|
413
|
+
})], OAuthConsent);
|
|
414
|
+
|
|
415
|
+
//#endregion
|
|
416
|
+
//#region src/models/OAuthRefreshToken.ts
|
|
417
|
+
var OAuthRefreshToken = class OAuthRefreshToken extends Model {};
|
|
418
|
+
__decorate([PrimaryKey, Column({
|
|
419
|
+
type: DataType.STRING,
|
|
420
|
+
allowNull: false
|
|
421
|
+
}), __decorateMetadata("design:type", String)], OAuthRefreshToken.prototype, "tokenHash", void 0);
|
|
422
|
+
__decorate([Column({
|
|
423
|
+
type: DataType.STRING,
|
|
424
|
+
allowNull: false
|
|
425
|
+
}), __decorateMetadata("design:type", String)], OAuthRefreshToken.prototype, "clientId", void 0);
|
|
426
|
+
__decorate([Column({
|
|
427
|
+
type: DataType.STRING,
|
|
428
|
+
allowNull: false
|
|
429
|
+
}), __decorateMetadata("design:type", String)], OAuthRefreshToken.prototype, "subject", void 0);
|
|
430
|
+
__decorate([Column({
|
|
431
|
+
type: DataType.JSONB,
|
|
432
|
+
allowNull: false
|
|
433
|
+
}), __decorateMetadata("design:type", Array)], OAuthRefreshToken.prototype, "scopes", void 0);
|
|
434
|
+
__decorate([Column({
|
|
435
|
+
type: DataType.DATE,
|
|
436
|
+
allowNull: false
|
|
437
|
+
}), __decorateMetadata("design:type", typeof Date === "undefined" ? Object : Date)], OAuthRefreshToken.prototype, "expiresAt", void 0);
|
|
438
|
+
__decorate([Column({
|
|
439
|
+
type: DataType.DATE,
|
|
440
|
+
allowNull: true
|
|
441
|
+
}), __decorateMetadata("design:type", Object)], OAuthRefreshToken.prototype, "consumedAt", void 0);
|
|
442
|
+
OAuthRefreshToken = __decorate([Table({
|
|
443
|
+
tableName: "oauth_refresh_tokens",
|
|
444
|
+
modelName: "oauthRefreshToken",
|
|
445
|
+
indexes: [{
|
|
446
|
+
fields: ["client_id", "subject"]
|
|
447
|
+
}, {
|
|
448
|
+
fields: ["expires_at"]
|
|
449
|
+
}]
|
|
450
|
+
})], OAuthRefreshToken);
|
|
451
|
+
|
|
452
|
+
//#endregion
|
|
453
|
+
//#region src/models/index.ts
|
|
454
|
+
/**
|
|
455
|
+
* The OAuth data model, ready to register alongside the application's own
|
|
456
|
+
* models so `ttoss-postgresdb sync` and `erd` cover these tables like any
|
|
457
|
+
* other instead of them being a side-channel schema the CLI cannot see.
|
|
458
|
+
*
|
|
459
|
+
* @example
|
|
460
|
+
* ```typescript
|
|
461
|
+
* import { oauthModels } from '@ttoss/auth-postgresdb';
|
|
462
|
+
* import { initialize } from '@ttoss/postgresdb';
|
|
463
|
+
*
|
|
464
|
+
* export const db = await initialize({ models: { ...oauthModels, User } });
|
|
465
|
+
* ```
|
|
466
|
+
*/
|
|
467
|
+
var oauthModels = {
|
|
468
|
+
OAuthAuthCode,
|
|
469
|
+
OAuthClient,
|
|
470
|
+
OAuthConsent,
|
|
471
|
+
OAuthRefreshToken
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
//#endregion
|
|
475
|
+
export { OAuthAuthCode, OAuthClient, OAuthConsent, OAuthRefreshToken, createAuthCodeStore, createClientStore, createConsentStore, createPostgresdbOAuthStores, createRefreshTokenStore, oauthModels };
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ttoss/auth-postgresdb",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Durable Postgres OAuth stores and models for @ttoss/auth-core",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"auth",
|
|
7
|
+
"oauth",
|
|
8
|
+
"postgres",
|
|
9
|
+
"sequelize",
|
|
10
|
+
"ttoss"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/ttoss/ttoss.git",
|
|
15
|
+
"directory": "packages/auth-postgresdb"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"author": "ttoss",
|
|
19
|
+
"contributors": [
|
|
20
|
+
"Pedro Arantes <pedro@arantespp.com> (https://arantespp.com)"
|
|
21
|
+
],
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"type": "module",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"import": "./dist/index.mjs",
|
|
27
|
+
"require": "./dist/index.cjs",
|
|
28
|
+
"types": "./dist/index.d.mts"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"jest": "^30.4.2",
|
|
36
|
+
"tsdown": "^0.22.2",
|
|
37
|
+
"@ttoss/config": "^1.37.17",
|
|
38
|
+
"@ttoss/postgresdb": "^0.11.0",
|
|
39
|
+
"@ttoss/auth-core": "^0.13.0"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"@ttoss/auth-core": "^0.13.0",
|
|
43
|
+
"@ttoss/postgresdb": "^0.11.0"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public",
|
|
47
|
+
"provenance": true
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsdown",
|
|
51
|
+
"pretest": "pnpm run build",
|
|
52
|
+
"test": "jest --projects tests/unit"
|
|
53
|
+
}
|
|
54
|
+
}
|