@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/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024, Terezinha Tech Operations (ttoss)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# @ttoss/auth-postgresdb
|
|
2
|
+
|
|
3
|
+
Durable Postgres persistence for the OAuth 2.1 authorization server in [`@ttoss/auth-core`](https://ttoss.dev/docs/modules/packages/auth-core): the Sequelize models for the RFC data model, plus the store adapters `createOAuthHandlers`, `createRefreshRotation`, and `createRedirectConsentOnAuthorize` expect.
|
|
4
|
+
|
|
5
|
+
`@ttoss/auth-core` ships `Map`-backed stores for tests and local development; this package is what production swaps in behind the same interfaces, without reaching around your ORM to inject a raw `pg` query runner.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @ttoss/auth-postgresdb @ttoss/auth-core @ttoss/postgresdb
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
Register `oauthModels` alongside your own models so `ttoss-postgresdb sync` and `erd` manage these tables like any other, then build the stores from the `db` handle:
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import {
|
|
19
|
+
createPostgresdbOAuthStores,
|
|
20
|
+
oauthModels,
|
|
21
|
+
} from '@ttoss/auth-postgresdb';
|
|
22
|
+
import { initialize } from '@ttoss/postgresdb';
|
|
23
|
+
|
|
24
|
+
import { User } from './models/User';
|
|
25
|
+
|
|
26
|
+
export const db = await initialize({ models: { ...oauthModels, User } });
|
|
27
|
+
|
|
28
|
+
export const { clientStore, authCodeStore, consentStore, refreshTokenStore } =
|
|
29
|
+
createPostgresdbOAuthStores({ db });
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The stores drop straight into the OAuth server:
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { createRefreshRotation } from '@ttoss/auth-core';
|
|
36
|
+
import { oauthServer } from '@ttoss/http-server-auth';
|
|
37
|
+
|
|
38
|
+
const refresh = createRefreshRotation({ store: refreshTokenStore });
|
|
39
|
+
|
|
40
|
+
const authServer = oauthServer({
|
|
41
|
+
issuer: 'https://api.example.com',
|
|
42
|
+
clientStore,
|
|
43
|
+
authCodeStore,
|
|
44
|
+
onRefreshToken: refresh.onRefreshToken,
|
|
45
|
+
// …issueTokens, onAuthorize…
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Each store is also exported on its own (`createClientStore`, `createAuthCodeStore`, `createConsentStore`, `createRefreshTokenStore`) for apps that register only some of the models.
|
|
50
|
+
|
|
51
|
+
## Schema
|
|
52
|
+
|
|
53
|
+
| Model | Table | Primary key |
|
|
54
|
+
| ------------------- | ---------------------- | ---------------- |
|
|
55
|
+
| `OAuthClient` | `oauth_clients` | `client_id` |
|
|
56
|
+
| `OAuthAuthCode` | `oauth_auth_codes` | `code_hash` |
|
|
57
|
+
| `OAuthConsent` | `oauth_consents` | `code_challenge` |
|
|
58
|
+
| `OAuthRefreshToken` | `oauth_refresh_tokens` | `token_hash` |
|
|
59
|
+
|
|
60
|
+
Credentials are stored by SHA-256 hash, never in plaintext, so a database dump yields nothing replayable. `OAuthClient` keeps the registered RFC 7591 fields in their own columns and any additional submitted metadata in a `metadata` JSONB column, so a registration document round-trips unchanged.
|
|
61
|
+
|
|
62
|
+
## Two traps these adapters absorb
|
|
63
|
+
|
|
64
|
+
**Authorization codes are hashed at rest.** `AuthCodeStore.get` is handed the plaintext code, but a code travels through a browser redirect and a client's URL bar. The engine never compares the returned `code` against anything — it reads only `clientId`, `redirectUri`, `codeChallenge`, `scopes`, `subject`, and `expiresAt` — so the adapter hashes to find the row and echoes the presented value back.
|
|
65
|
+
|
|
66
|
+
**A live refresh token reports no `consumedAt` at all.** `createRefreshRotation` treats `stored.consumedAt !== undefined` as reuse. A nullable timestamp column reads back as `null`, which is `!== undefined`, so a naive adapter makes every live token look consumed: the first refresh is treated as a replay and revokes the owner's entire token set — "refresh works once, then the client must re-authorize forever". The adapter omits the key instead of setting it to `null`.
|
|
67
|
+
|
|
68
|
+
## Consent
|
|
69
|
+
|
|
70
|
+
`consentStore` satisfies the `ConsentGrantStore` that `createRedirectConsentOnAuthorize` consumes, and adds `saveConsentGrant` for the write your consent page performs on approval. It is the single-use handoff keyed by the PKCE `code_challenge` — not a durable "user X trusts client Y" record, which is an app-level authorization decision and belongs in your own schema.
|
|
71
|
+
|
|
72
|
+
## Related
|
|
73
|
+
|
|
74
|
+
- [OAuth Authorization Server](https://ttoss.dev/docs/engineering/guidelines/oauth-authorization-server) — the full server setup and the ttoss-vs-app responsibility split
|
|
75
|
+
- [MCP Server with OAuth](https://ttoss.dev/docs/engineering/guidelines/mcp-server-oauth) — the MCP application of these primitives
|
|
76
|
+
- [`@ttoss/postgresdb`](https://ttoss.dev/docs/modules/packages/postgresdb) — `initialize`, and the `sync` / `erd` CLI
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
/** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, {
|
|
3
|
+
value: 'Module'
|
|
4
|
+
});
|
|
5
|
+
let _ttoss_auth_core = require("@ttoss/auth-core");
|
|
6
|
+
let _ttoss_postgresdb = require("@ttoss/postgresdb");
|
|
7
|
+
|
|
8
|
+
//#region src/stores/createAuthCodeStore.ts
|
|
9
|
+
/**
|
|
10
|
+
* Creates an {@link AuthCodeStore} backed by the `oauth_auth_codes` table,
|
|
11
|
+
* storing codes by SHA-256 hash.
|
|
12
|
+
*
|
|
13
|
+
* The engine hands the store the plaintext code on every call and never compares
|
|
14
|
+
* the returned `code` against anything — it reads only `clientId`,
|
|
15
|
+
* `redirectUri`, `codeChallenge`, `scopes`, `subject`, and `expiresAt`. So the
|
|
16
|
+
* adapter hashes to find the row and echoes the presented value back, and a
|
|
17
|
+
* database dump yields no replayable codes.
|
|
18
|
+
*/
|
|
19
|
+
var createAuthCodeStore = ({
|
|
20
|
+
model
|
|
21
|
+
}) => {
|
|
22
|
+
return {
|
|
23
|
+
save: async code => {
|
|
24
|
+
await model.upsert({
|
|
25
|
+
codeHash: (0, _ttoss_auth_core.hashAuthorizationCode)({
|
|
26
|
+
code: code.code
|
|
27
|
+
}),
|
|
28
|
+
clientId: code.clientId,
|
|
29
|
+
redirectUri: code.redirectUri,
|
|
30
|
+
codeChallenge: code.codeChallenge,
|
|
31
|
+
scopes: code.scopes,
|
|
32
|
+
subject: code.subject,
|
|
33
|
+
expiresAt: new Date(code.expiresAt)
|
|
34
|
+
});
|
|
35
|
+
},
|
|
36
|
+
get: async code => {
|
|
37
|
+
const row = await model.findByPk((0, _ttoss_auth_core.hashAuthorizationCode)({
|
|
38
|
+
code
|
|
39
|
+
}));
|
|
40
|
+
if (!row) return;
|
|
41
|
+
return {
|
|
42
|
+
code,
|
|
43
|
+
clientId: row.clientId,
|
|
44
|
+
redirectUri: row.redirectUri,
|
|
45
|
+
codeChallenge: row.codeChallenge,
|
|
46
|
+
scopes: row.scopes,
|
|
47
|
+
subject: row.subject,
|
|
48
|
+
expiresAt: row.expiresAt.getTime()
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
delete: async code => {
|
|
52
|
+
await model.destroy({
|
|
53
|
+
where: {
|
|
54
|
+
codeHash: (0, _ttoss_auth_core.hashAuthorizationCode)({
|
|
55
|
+
code
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/stores/createClientStore.ts
|
|
65
|
+
/**
|
|
66
|
+
* Registration fields that have their own column. Everything else a client
|
|
67
|
+
* submits goes to `metadata`, so the document round-trips unchanged.
|
|
68
|
+
*/
|
|
69
|
+
var COLUMN_FIELDS = ["client_id", "client_secret", "client_name", "redirect_uris", "grant_types", "response_types", "token_endpoint_auth_method", "scope", "client_id_issued_at"];
|
|
70
|
+
var toRecord = row => {
|
|
71
|
+
return {
|
|
72
|
+
...row.metadata,
|
|
73
|
+
client_id: row.clientId,
|
|
74
|
+
redirect_uris: row.redirectUris,
|
|
75
|
+
...(row.clientSecret !== null && {
|
|
76
|
+
client_secret: row.clientSecret
|
|
77
|
+
}),
|
|
78
|
+
...(row.clientName !== null && {
|
|
79
|
+
client_name: row.clientName
|
|
80
|
+
}),
|
|
81
|
+
...(row.grantTypes !== null && {
|
|
82
|
+
grant_types: row.grantTypes
|
|
83
|
+
}),
|
|
84
|
+
...(row.responseTypes !== null && {
|
|
85
|
+
response_types: row.responseTypes
|
|
86
|
+
}),
|
|
87
|
+
...(row.tokenEndpointAuthMethod !== null && {
|
|
88
|
+
token_endpoint_auth_method: row.tokenEndpointAuthMethod
|
|
89
|
+
}),
|
|
90
|
+
...(row.scope !== null && {
|
|
91
|
+
scope: row.scope
|
|
92
|
+
}),
|
|
93
|
+
...(row.clientIdIssuedAt !== null && {
|
|
94
|
+
client_id_issued_at: Number(row.clientIdIssuedAt)
|
|
95
|
+
})
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
var toMetadata = client => {
|
|
99
|
+
const metadata = {};
|
|
100
|
+
for (const [key, value] of Object.entries(client)) if (!COLUMN_FIELDS.includes(key)) metadata[key] = value;
|
|
101
|
+
return metadata;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Creates a {@link ClientStore} backed by the `oauth_clients` table.
|
|
105
|
+
*
|
|
106
|
+
* `register` upserts, so re-registering an existing `client_id` replaces the
|
|
107
|
+
* stored document rather than failing on the primary key.
|
|
108
|
+
*/
|
|
109
|
+
var createClientStore = ({
|
|
110
|
+
model
|
|
111
|
+
}) => {
|
|
112
|
+
return {
|
|
113
|
+
get: async clientId => {
|
|
114
|
+
const row = await model.findByPk(clientId);
|
|
115
|
+
return row ? toRecord(row) : void 0;
|
|
116
|
+
},
|
|
117
|
+
register: async client => {
|
|
118
|
+
await model.upsert({
|
|
119
|
+
clientId: client.client_id,
|
|
120
|
+
clientSecret: client.client_secret ?? null,
|
|
121
|
+
clientName: client.client_name ?? null,
|
|
122
|
+
redirectUris: client.redirect_uris,
|
|
123
|
+
grantTypes: client.grant_types ?? null,
|
|
124
|
+
responseTypes: client.response_types ?? null,
|
|
125
|
+
tokenEndpointAuthMethod: client.token_endpoint_auth_method ?? null,
|
|
126
|
+
scope: client.scope ?? null,
|
|
127
|
+
clientIdIssuedAt: client.client_id_issued_at ?? null,
|
|
128
|
+
metadata: toMetadata(client)
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/stores/createConsentStore.ts
|
|
136
|
+
/**
|
|
137
|
+
* Creates a consent store backed by the `oauth_consents` table, for use with
|
|
138
|
+
* `createRedirectConsentOnAuthorize`.
|
|
139
|
+
*
|
|
140
|
+
* Reads and deletes satisfy `ConsentGrantStore`; `saveConsentGrant` covers the
|
|
141
|
+
* write the consent page performs. Grants are single-use — the `onAuthorize`
|
|
142
|
+
* hook deletes each one as it consumes it.
|
|
143
|
+
*/
|
|
144
|
+
var createConsentStore = ({
|
|
145
|
+
model
|
|
146
|
+
}) => {
|
|
147
|
+
return {
|
|
148
|
+
saveConsentGrant: async ({
|
|
149
|
+
codeChallenge,
|
|
150
|
+
subject,
|
|
151
|
+
scopes,
|
|
152
|
+
expiresAt
|
|
153
|
+
}) => {
|
|
154
|
+
await model.upsert({
|
|
155
|
+
codeChallenge,
|
|
156
|
+
subject,
|
|
157
|
+
scopes,
|
|
158
|
+
expiresAt: new Date(expiresAt)
|
|
159
|
+
});
|
|
160
|
+
},
|
|
161
|
+
getConsentGrant: async ({
|
|
162
|
+
codeChallenge
|
|
163
|
+
}) => {
|
|
164
|
+
const row = await model.findByPk(codeChallenge);
|
|
165
|
+
if (!row) return;
|
|
166
|
+
return {
|
|
167
|
+
subject: row.subject,
|
|
168
|
+
scopes: row.scopes,
|
|
169
|
+
expiresAt: row.expiresAt.getTime()
|
|
170
|
+
};
|
|
171
|
+
},
|
|
172
|
+
deleteConsentGrant: async ({
|
|
173
|
+
codeChallenge
|
|
174
|
+
}) => {
|
|
175
|
+
await model.destroy({
|
|
176
|
+
where: {
|
|
177
|
+
codeChallenge
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
//#endregion
|
|
185
|
+
//#region src/stores/createRefreshTokenStore.ts
|
|
186
|
+
/**
|
|
187
|
+
* Creates a {@link RefreshTokenStore} backed by the `oauth_refresh_tokens`
|
|
188
|
+
* table, keyed by token hash and by the `(clientId, subject)` owner that
|
|
189
|
+
* `deleteByOwner` revokes on reuse detection.
|
|
190
|
+
*/
|
|
191
|
+
var createRefreshTokenStore = ({
|
|
192
|
+
model
|
|
193
|
+
}) => {
|
|
194
|
+
return {
|
|
195
|
+
save: async token => {
|
|
196
|
+
await model.upsert({
|
|
197
|
+
tokenHash: token.tokenHash,
|
|
198
|
+
clientId: token.clientId,
|
|
199
|
+
subject: token.subject,
|
|
200
|
+
scopes: token.scopes,
|
|
201
|
+
expiresAt: new Date(token.expiresAt),
|
|
202
|
+
consumedAt: token.consumedAt === void 0 ? null : new Date(token.consumedAt)
|
|
203
|
+
});
|
|
204
|
+
},
|
|
205
|
+
get: async tokenHash => {
|
|
206
|
+
const row = await model.findByPk(tokenHash);
|
|
207
|
+
if (!row) return;
|
|
208
|
+
return {
|
|
209
|
+
tokenHash: row.tokenHash,
|
|
210
|
+
clientId: row.clientId,
|
|
211
|
+
subject: row.subject,
|
|
212
|
+
scopes: row.scopes,
|
|
213
|
+
expiresAt: row.expiresAt.getTime(),
|
|
214
|
+
/**
|
|
215
|
+
* The key is omitted, not set to `null`. Rotation tests
|
|
216
|
+
* `stored.consumedAt !== undefined` to detect reuse, and a nullable
|
|
217
|
+
* timestamp column reads back as `null` — which would make every live
|
|
218
|
+
* token look consumed, so the first refresh would be treated as a
|
|
219
|
+
* replay and revoke the owner's entire token set.
|
|
220
|
+
*/
|
|
221
|
+
...(row.consumedAt !== null && {
|
|
222
|
+
consumedAt: row.consumedAt.getTime()
|
|
223
|
+
})
|
|
224
|
+
};
|
|
225
|
+
},
|
|
226
|
+
delete: async tokenHash => {
|
|
227
|
+
await model.destroy({
|
|
228
|
+
where: {
|
|
229
|
+
tokenHash
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
},
|
|
233
|
+
deleteByOwner: async ({
|
|
234
|
+
clientId,
|
|
235
|
+
subject
|
|
236
|
+
}) => {
|
|
237
|
+
await model.destroy({
|
|
238
|
+
where: {
|
|
239
|
+
clientId,
|
|
240
|
+
subject
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region src/createPostgresdbOAuthStores.ts
|
|
249
|
+
/**
|
|
250
|
+
* Creates every durable OAuth store from a `@ttoss/postgresdb` `db` handle.
|
|
251
|
+
*
|
|
252
|
+
* The stores are mechanical adapters between the `@ttoss/auth-core` store
|
|
253
|
+
* contracts and Sequelize, so an app that already uses `@ttoss/postgresdb` does
|
|
254
|
+
* not have to write them — nor reach around its own ORM to inject a raw `pg`
|
|
255
|
+
* query runner.
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* ```typescript
|
|
259
|
+
* import { createPostgresdbOAuthStores, oauthModels } from '@ttoss/auth-postgresdb';
|
|
260
|
+
* import { initialize } from '@ttoss/postgresdb';
|
|
261
|
+
*
|
|
262
|
+
* const db = await initialize({ models: { ...oauthModels, User } });
|
|
263
|
+
*
|
|
264
|
+
* const { clientStore, authCodeStore, consentStore, refreshTokenStore } =
|
|
265
|
+
* createPostgresdbOAuthStores({ db });
|
|
266
|
+
* ```
|
|
267
|
+
*/
|
|
268
|
+
var createPostgresdbOAuthStores = ({
|
|
269
|
+
db
|
|
270
|
+
}) => {
|
|
271
|
+
return {
|
|
272
|
+
clientStore: createClientStore({
|
|
273
|
+
model: db.OAuthClient
|
|
274
|
+
}),
|
|
275
|
+
authCodeStore: createAuthCodeStore({
|
|
276
|
+
model: db.OAuthAuthCode
|
|
277
|
+
}),
|
|
278
|
+
consentStore: createConsentStore({
|
|
279
|
+
model: db.OAuthConsent
|
|
280
|
+
}),
|
|
281
|
+
refreshTokenStore: createRefreshTokenStore({
|
|
282
|
+
model: db.OAuthRefreshToken
|
|
283
|
+
})
|
|
284
|
+
};
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
//#endregion
|
|
288
|
+
//#region \0@oxc-project+runtime@0.134.0/helpers/esm/decorateMetadata.js
|
|
289
|
+
function __decorateMetadata(k, v) {
|
|
290
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
//#endregion
|
|
294
|
+
//#region \0@oxc-project+runtime@0.134.0/helpers/esm/decorate.js
|
|
295
|
+
function __decorate(decorators, target, key, desc) {
|
|
296
|
+
var c = arguments.length,
|
|
297
|
+
r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc,
|
|
298
|
+
d;
|
|
299
|
+
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;
|
|
300
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
//#endregion
|
|
304
|
+
//#region src/models/OAuthAuthCode.ts
|
|
305
|
+
var OAuthAuthCode = class OAuthAuthCode extends _ttoss_postgresdb.Model {};
|
|
306
|
+
__decorate([_ttoss_postgresdb.PrimaryKey, (0, _ttoss_postgresdb.Column)({
|
|
307
|
+
type: _ttoss_postgresdb.DataType.STRING,
|
|
308
|
+
allowNull: false
|
|
309
|
+
}), __decorateMetadata("design:type", String)], OAuthAuthCode.prototype, "codeHash", void 0);
|
|
310
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
311
|
+
type: _ttoss_postgresdb.DataType.STRING,
|
|
312
|
+
allowNull: false
|
|
313
|
+
}), __decorateMetadata("design:type", String)], OAuthAuthCode.prototype, "clientId", void 0);
|
|
314
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
315
|
+
type: _ttoss_postgresdb.DataType.TEXT,
|
|
316
|
+
allowNull: false
|
|
317
|
+
}), __decorateMetadata("design:type", String)], OAuthAuthCode.prototype, "redirectUri", void 0);
|
|
318
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
319
|
+
type: _ttoss_postgresdb.DataType.STRING,
|
|
320
|
+
allowNull: false
|
|
321
|
+
}), __decorateMetadata("design:type", String)], OAuthAuthCode.prototype, "codeChallenge", void 0);
|
|
322
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
323
|
+
type: _ttoss_postgresdb.DataType.JSONB,
|
|
324
|
+
allowNull: false
|
|
325
|
+
}), __decorateMetadata("design:type", Array)], OAuthAuthCode.prototype, "scopes", void 0);
|
|
326
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
327
|
+
type: _ttoss_postgresdb.DataType.STRING,
|
|
328
|
+
allowNull: false
|
|
329
|
+
}), __decorateMetadata("design:type", String)], OAuthAuthCode.prototype, "subject", void 0);
|
|
330
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
331
|
+
type: _ttoss_postgresdb.DataType.DATE,
|
|
332
|
+
allowNull: false
|
|
333
|
+
}), __decorateMetadata("design:type", typeof Date === "undefined" ? Object : Date)], OAuthAuthCode.prototype, "expiresAt", void 0);
|
|
334
|
+
OAuthAuthCode = __decorate([(0, _ttoss_postgresdb.Table)({
|
|
335
|
+
tableName: "oauth_auth_codes",
|
|
336
|
+
modelName: "oauthAuthCode",
|
|
337
|
+
indexes: [{
|
|
338
|
+
fields: ["expires_at"]
|
|
339
|
+
}]
|
|
340
|
+
})], OAuthAuthCode);
|
|
341
|
+
|
|
342
|
+
//#endregion
|
|
343
|
+
//#region src/models/OAuthClient.ts
|
|
344
|
+
var OAuthClient = class OAuthClient extends _ttoss_postgresdb.Model {};
|
|
345
|
+
__decorate([_ttoss_postgresdb.PrimaryKey, (0, _ttoss_postgresdb.Column)({
|
|
346
|
+
type: _ttoss_postgresdb.DataType.STRING,
|
|
347
|
+
allowNull: false
|
|
348
|
+
}), __decorateMetadata("design:type", String)], OAuthClient.prototype, "clientId", void 0);
|
|
349
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
350
|
+
type: _ttoss_postgresdb.DataType.STRING,
|
|
351
|
+
allowNull: true
|
|
352
|
+
}), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "clientSecret", void 0);
|
|
353
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
354
|
+
type: _ttoss_postgresdb.DataType.STRING,
|
|
355
|
+
allowNull: true
|
|
356
|
+
}), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "clientName", void 0);
|
|
357
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
358
|
+
type: _ttoss_postgresdb.DataType.JSONB,
|
|
359
|
+
allowNull: false
|
|
360
|
+
}), __decorateMetadata("design:type", Array)], OAuthClient.prototype, "redirectUris", void 0);
|
|
361
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
362
|
+
type: _ttoss_postgresdb.DataType.JSONB,
|
|
363
|
+
allowNull: true
|
|
364
|
+
}), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "grantTypes", void 0);
|
|
365
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
366
|
+
type: _ttoss_postgresdb.DataType.JSONB,
|
|
367
|
+
allowNull: true
|
|
368
|
+
}), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "responseTypes", void 0);
|
|
369
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
370
|
+
type: _ttoss_postgresdb.DataType.STRING,
|
|
371
|
+
allowNull: true
|
|
372
|
+
}), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "tokenEndpointAuthMethod", void 0);
|
|
373
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
374
|
+
type: _ttoss_postgresdb.DataType.STRING,
|
|
375
|
+
allowNull: true
|
|
376
|
+
}), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "scope", void 0);
|
|
377
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
378
|
+
type: _ttoss_postgresdb.DataType.BIGINT,
|
|
379
|
+
allowNull: true
|
|
380
|
+
}), __decorateMetadata("design:type", Object)], OAuthClient.prototype, "clientIdIssuedAt", void 0);
|
|
381
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
382
|
+
type: _ttoss_postgresdb.DataType.JSONB,
|
|
383
|
+
allowNull: false,
|
|
384
|
+
defaultValue: {}
|
|
385
|
+
}), __decorateMetadata("design:type", typeof Record === "undefined" ? Object : Record)], OAuthClient.prototype, "metadata", void 0);
|
|
386
|
+
OAuthClient = __decorate([(0, _ttoss_postgresdb.Table)({
|
|
387
|
+
tableName: "oauth_clients",
|
|
388
|
+
modelName: "oauthClient"
|
|
389
|
+
})], OAuthClient);
|
|
390
|
+
|
|
391
|
+
//#endregion
|
|
392
|
+
//#region src/models/OAuthConsent.ts
|
|
393
|
+
var OAuthConsent = class OAuthConsent extends _ttoss_postgresdb.Model {};
|
|
394
|
+
__decorate([_ttoss_postgresdb.PrimaryKey, (0, _ttoss_postgresdb.Column)({
|
|
395
|
+
type: _ttoss_postgresdb.DataType.STRING,
|
|
396
|
+
allowNull: false
|
|
397
|
+
}), __decorateMetadata("design:type", String)], OAuthConsent.prototype, "codeChallenge", void 0);
|
|
398
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
399
|
+
type: _ttoss_postgresdb.DataType.STRING,
|
|
400
|
+
allowNull: false
|
|
401
|
+
}), __decorateMetadata("design:type", String)], OAuthConsent.prototype, "subject", void 0);
|
|
402
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
403
|
+
type: _ttoss_postgresdb.DataType.JSONB,
|
|
404
|
+
allowNull: false
|
|
405
|
+
}), __decorateMetadata("design:type", Array)], OAuthConsent.prototype, "scopes", void 0);
|
|
406
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
407
|
+
type: _ttoss_postgresdb.DataType.DATE,
|
|
408
|
+
allowNull: false
|
|
409
|
+
}), __decorateMetadata("design:type", typeof Date === "undefined" ? Object : Date)], OAuthConsent.prototype, "expiresAt", void 0);
|
|
410
|
+
OAuthConsent = __decorate([(0, _ttoss_postgresdb.Table)({
|
|
411
|
+
tableName: "oauth_consents",
|
|
412
|
+
modelName: "oauthConsent",
|
|
413
|
+
indexes: [{
|
|
414
|
+
fields: ["expires_at"]
|
|
415
|
+
}]
|
|
416
|
+
})], OAuthConsent);
|
|
417
|
+
|
|
418
|
+
//#endregion
|
|
419
|
+
//#region src/models/OAuthRefreshToken.ts
|
|
420
|
+
var OAuthRefreshToken = class OAuthRefreshToken extends _ttoss_postgresdb.Model {};
|
|
421
|
+
__decorate([_ttoss_postgresdb.PrimaryKey, (0, _ttoss_postgresdb.Column)({
|
|
422
|
+
type: _ttoss_postgresdb.DataType.STRING,
|
|
423
|
+
allowNull: false
|
|
424
|
+
}), __decorateMetadata("design:type", String)], OAuthRefreshToken.prototype, "tokenHash", void 0);
|
|
425
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
426
|
+
type: _ttoss_postgresdb.DataType.STRING,
|
|
427
|
+
allowNull: false
|
|
428
|
+
}), __decorateMetadata("design:type", String)], OAuthRefreshToken.prototype, "clientId", void 0);
|
|
429
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
430
|
+
type: _ttoss_postgresdb.DataType.STRING,
|
|
431
|
+
allowNull: false
|
|
432
|
+
}), __decorateMetadata("design:type", String)], OAuthRefreshToken.prototype, "subject", void 0);
|
|
433
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
434
|
+
type: _ttoss_postgresdb.DataType.JSONB,
|
|
435
|
+
allowNull: false
|
|
436
|
+
}), __decorateMetadata("design:type", Array)], OAuthRefreshToken.prototype, "scopes", void 0);
|
|
437
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
438
|
+
type: _ttoss_postgresdb.DataType.DATE,
|
|
439
|
+
allowNull: false
|
|
440
|
+
}), __decorateMetadata("design:type", typeof Date === "undefined" ? Object : Date)], OAuthRefreshToken.prototype, "expiresAt", void 0);
|
|
441
|
+
__decorate([(0, _ttoss_postgresdb.Column)({
|
|
442
|
+
type: _ttoss_postgresdb.DataType.DATE,
|
|
443
|
+
allowNull: true
|
|
444
|
+
}), __decorateMetadata("design:type", Object)], OAuthRefreshToken.prototype, "consumedAt", void 0);
|
|
445
|
+
OAuthRefreshToken = __decorate([(0, _ttoss_postgresdb.Table)({
|
|
446
|
+
tableName: "oauth_refresh_tokens",
|
|
447
|
+
modelName: "oauthRefreshToken",
|
|
448
|
+
indexes: [{
|
|
449
|
+
fields: ["client_id", "subject"]
|
|
450
|
+
}, {
|
|
451
|
+
fields: ["expires_at"]
|
|
452
|
+
}]
|
|
453
|
+
})], OAuthRefreshToken);
|
|
454
|
+
|
|
455
|
+
//#endregion
|
|
456
|
+
//#region src/models/index.ts
|
|
457
|
+
/**
|
|
458
|
+
* The OAuth data model, ready to register alongside the application's own
|
|
459
|
+
* models so `ttoss-postgresdb sync` and `erd` cover these tables like any
|
|
460
|
+
* other instead of them being a side-channel schema the CLI cannot see.
|
|
461
|
+
*
|
|
462
|
+
* @example
|
|
463
|
+
* ```typescript
|
|
464
|
+
* import { oauthModels } from '@ttoss/auth-postgresdb';
|
|
465
|
+
* import { initialize } from '@ttoss/postgresdb';
|
|
466
|
+
*
|
|
467
|
+
* export const db = await initialize({ models: { ...oauthModels, User } });
|
|
468
|
+
* ```
|
|
469
|
+
*/
|
|
470
|
+
var oauthModels = {
|
|
471
|
+
OAuthAuthCode,
|
|
472
|
+
OAuthClient,
|
|
473
|
+
OAuthConsent,
|
|
474
|
+
OAuthRefreshToken
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
//#endregion
|
|
478
|
+
Object.defineProperty(exports, 'OAuthAuthCode', {
|
|
479
|
+
enumerable: true,
|
|
480
|
+
get: function () {
|
|
481
|
+
return OAuthAuthCode;
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
Object.defineProperty(exports, 'OAuthClient', {
|
|
485
|
+
enumerable: true,
|
|
486
|
+
get: function () {
|
|
487
|
+
return OAuthClient;
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
Object.defineProperty(exports, 'OAuthConsent', {
|
|
491
|
+
enumerable: true,
|
|
492
|
+
get: function () {
|
|
493
|
+
return OAuthConsent;
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
Object.defineProperty(exports, 'OAuthRefreshToken', {
|
|
497
|
+
enumerable: true,
|
|
498
|
+
get: function () {
|
|
499
|
+
return OAuthRefreshToken;
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
exports.createAuthCodeStore = createAuthCodeStore;
|
|
503
|
+
exports.createClientStore = createClientStore;
|
|
504
|
+
exports.createConsentStore = createConsentStore;
|
|
505
|
+
exports.createPostgresdbOAuthStores = createPostgresdbOAuthStores;
|
|
506
|
+
exports.createRefreshTokenStore = createRefreshTokenStore;
|
|
507
|
+
exports.oauthModels = oauthModels;
|