@adonis-agora/authkit-server 1.0.0-rc.10 → 1.0.0-rc.12

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 (47) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +1 -1
  3. package/build/index.d.ts +2 -1
  4. package/build/index.js +1 -0
  5. package/build/providers/authkit_server_provider.js +16 -4
  6. package/build/src/accounts/account_store.d.ts +7 -7
  7. package/build/src/accounts/lucid_account_store.d.ts +3 -3
  8. package/build/src/accounts/lucid_account_store.js +43 -17
  9. package/build/src/accounts/lucid_store/mfa.js +3 -3
  10. package/build/src/accounts/lucid_store/organization_models.d.ts +18 -3
  11. package/build/src/accounts/lucid_store/organization_models.js +35 -3
  12. package/build/src/accounts/lucid_store/organizations.d.ts +2 -2
  13. package/build/src/accounts/lucid_store/organizations.js +35 -32
  14. package/build/src/accounts/lucid_store/password_hygiene.js +4 -2
  15. package/build/src/accounts/lucid_store/shared.d.ts +16 -3
  16. package/build/src/accounts/lucid_store/shared.js +13 -10
  17. package/build/src/accounts/lucid_store/webauthn.js +1 -1
  18. package/build/src/adapters/database_adapter.d.ts +7 -1
  19. package/build/src/adapters/database_adapter.js +24 -13
  20. package/build/src/adapters/factory.d.ts +20 -2
  21. package/build/src/adapters/factory.js +8 -4
  22. package/build/src/agents/delegation_store.d.ts +5 -1
  23. package/build/src/agents/delegation_store.js +34 -21
  24. package/build/src/agents/extension.d.ts +16 -2
  25. package/build/src/agents/registry_store.d.ts +1 -0
  26. package/build/src/agents/registry_store.js +10 -8
  27. package/build/src/agents/runtime.js +6 -2
  28. package/build/src/commands/expire_scan_command.js +2 -3
  29. package/build/src/commands/settings_commands.js +5 -5
  30. package/build/src/define_config.d.ts +12 -1
  31. package/build/src/define_config.js +34 -3
  32. package/build/src/doctor/agora_checks.js +13 -0
  33. package/build/src/doctor/checks.js +2 -2
  34. package/build/src/doctor/db_schema_check.d.ts +6 -0
  35. package/build/src/doctor/db_schema_check.js +87 -0
  36. package/build/src/host/admin_sessions_service.js +6 -2
  37. package/build/src/host/runtime_settings.d.ts +21 -6
  38. package/build/src/host/runtime_settings.js +29 -13
  39. package/build/src/keys/keystore_manager.js +2 -1
  40. package/build/src/keys/keystore_vault.d.ts +9 -1
  41. package/build/src/keys/keystore_vault.js +27 -9
  42. package/build/src/schema/ensure.d.ts +19 -1
  43. package/build/src/schema/ensure.js +54 -30
  44. package/build/src/schema/tables_location.d.ts +56 -0
  45. package/build/src/schema/tables_location.js +86 -0
  46. package/package.json +3 -3
  47. package/skills/authkit-idp-setup/SKILL.md +13 -7
@@ -24,9 +24,26 @@
24
24
  * ```
25
25
  */
26
26
  import type { AuthkitTable } from '../agents/extension.js';
27
+ /** Os nomes (sem schema) das tabelas que {@link ensureAuthkitSchema} garante. */
28
+ export declare const AUTHKIT_TABLE_NAMES: readonly string[];
27
29
  export interface EnsureSchemaOptions {
28
- /** Conexão Lucid a usar. Default: conexão primária. */
30
+ /**
31
+ * Conexão Lucid das tabelas do authkit (`schema.connection`). Default: conexão
32
+ * primária. Ignorada quando `db` já é um client (o `this.db` de uma migration).
33
+ */
29
34
  connection?: string;
35
+ /**
36
+ * Conexão Lucid do model da conta, onde vive a tabela da conta (a coluna
37
+ * `login_methods`). Default: a conexão primária — NÃO a das tabelas do authkit.
38
+ * O provider passa a do `accountStore` no boot. Ignorada quando `db` já é um client.
39
+ */
40
+ accountConnection?: string;
41
+ /**
42
+ * Database schema of the tables (MySQL: the database) — `schema.name`. Every statement
43
+ * names it (`"auth"."auth_settings"`), and it is created when missing. Never a
44
+ * `searchPath`. Ignored for the account table, which stays where the app put it.
45
+ */
46
+ schema?: string;
30
47
  /**
31
48
  * Tabelas de `personalAgents.extensions` (`tables` de cada uma), garantidas junto. O provider
32
49
  * passa as do config no boot.
@@ -64,6 +81,7 @@ export interface EnsureSchemaReport {
64
81
  */
65
82
  export declare function ensureAuthkitTables(db: any, tables: readonly AuthkitTable[], options?: {
66
83
  connection?: string;
84
+ schema?: string;
67
85
  }): Promise<Pick<EnsureSchemaReport, 'created' | 'altered' | 'indexed'>>;
68
86
  /**
69
87
  * Garante que as tabelas do authkit existem e têm todas as colunas que esta
@@ -23,6 +23,7 @@
23
23
  * }
24
24
  * ```
25
25
  */
26
+ import { assertSchemaSupported, authkitTable, authkitTablesClient, createDbSchema, validateSchemaName, } from './tables_location.js';
26
27
  /** Busca por conta (`account_id`) e limpeza dos expirados (`expires_at`). */
27
28
  const OIDC_PAYLOAD_INDEXES = [
28
29
  { name: 'authkit_oidc_payloads_account_idx', columns: ['model_name', 'account_id'] },
@@ -138,12 +139,12 @@ const TABLES = [
138
139
  },
139
140
  {
140
141
  name: 'auth_organization_members',
141
- create: (t) => {
142
+ create: (t, ctx) => {
142
143
  t.string('id').primary();
143
144
  t.string('organization_id')
144
145
  .notNullable()
145
146
  .references('id')
146
- .inTable('auth_organizations')
147
+ .inTable(ctx.table('auth_organizations'))
147
148
  .onDelete('CASCADE');
148
149
  t.string('account_id').notNullable();
149
150
  t.string('role').notNullable().defaultTo('member');
@@ -185,12 +186,12 @@ const TABLES = [
185
186
  },
186
187
  {
187
188
  name: 'auth_organization_invitations',
188
- create: (t) => {
189
+ create: (t, ctx) => {
189
190
  t.string('id').primary();
190
191
  t.string('organization_id')
191
192
  .notNullable()
192
193
  .references('id')
193
- .inTable('auth_organizations')
194
+ .inTable(ctx.table('auth_organizations'))
194
195
  .onDelete('CASCADE');
195
196
  t.string('email').notNullable();
196
197
  t.string('role').notNullable().defaultTo('member');
@@ -334,6 +335,8 @@ const TABLES = [
334
335
  },
335
336
  },
336
337
  ];
338
+ /** Os nomes (sem schema) das tabelas que {@link ensureAuthkitSchema} garante. */
339
+ export const AUTHKIT_TABLE_NAMES = TABLES.map((t) => t.name);
337
340
  /** Linhas de um `rawQuery`, no formato de cada driver (pg, mysql2, sqlite). */
338
341
  function catalogRows(result) {
339
342
  if (Array.isArray(result))
@@ -419,7 +422,10 @@ async function columnExists(conn, table, column) {
419
422
  async function indexExists(conn, table, name) {
420
423
  const dialect = conn.dialect?.name;
421
424
  if (dialect === 'postgres' || dialect === 'redshift') {
422
- const found = catalogRows(await conn.rawQuery('select to_regclass(?) as oid', [name]));
425
+ // Índice mora no schema da tabela: com schema explícito, o nome vai qualificado.
426
+ const [schema] = mysqlRelation(table);
427
+ const relation = pgRelation(schema ? `${schema}.${name}` : name);
428
+ const found = catalogRows(await conn.rawQuery('select to_regclass(?) as oid', [relation]));
423
429
  return found[0]?.oid != null;
424
430
  }
425
431
  if (dialect === 'mysql') {
@@ -440,11 +446,12 @@ async function indexExists(conn, table, name) {
440
446
  * Cria o índice quando falta. Idempotente: um índice já existente (inclusive
441
447
  * criado por outra instância no mesmo boot) não é erro.
442
448
  */
443
- async function ensureIndex(conn, table, index) {
449
+ async function ensureIndex(conn, loc, name, index) {
450
+ const table = authkitTable(loc, name);
444
451
  if ((await indexExists(conn, table, index.name)) === true)
445
452
  return false;
446
453
  try {
447
- await conn.schema.alterTable(table, (t) => t.index(index.columns, index.name));
454
+ await ddl(conn, loc).alterTable(name, (t) => t.index(index.columns, index.name));
448
455
  return true;
449
456
  }
450
457
  catch (error) {
@@ -457,12 +464,23 @@ async function ensureIndex(conn, table, index) {
457
464
  throw error;
458
465
  }
459
466
  }
467
+ /**
468
+ * O schema builder das tabelas do authkit: com `schema`, `withSchema` — o knex escreve
469
+ * `"schema"."tabela"` em todo DDL e mantém os nomes de índice derivados da tabela pura.
470
+ */
471
+ function ddl(conn, loc) {
472
+ return loc.schema ? conn.schema.withSchema(loc.schema) : conn.schema;
473
+ }
460
474
  /** Cria/completa as tabelas (o miolo de {@link ensureAuthkitSchema}). */
461
- async function ensureTables(conn, tables, report) {
475
+ async function ensureTables(conn, loc, tables, report) {
476
+ const context = { table: (name) => authkitTable(loc, name) };
477
+ if (loc.schema)
478
+ await createDbSchema(conn, loc.schema);
462
479
  for (const def of tables) {
463
- if (!(await tableExists(conn, def.name))) {
480
+ const table = authkitTable(loc, def.name);
481
+ if (!(await tableExists(conn, table))) {
464
482
  try {
465
- await conn.schema.createTable(def.name, def.create);
483
+ await ddl(conn, loc).createTable(def.name, (t) => def.create(t, context));
466
484
  report.created.push(def.name);
467
485
  continue;
468
486
  }
@@ -471,20 +489,20 @@ async function ensureTables(conn, tables, report) {
471
489
  * Corrida entre instâncias subindo juntas: se outra instância criou
472
490
  * a tabela entre o probe e o CREATE, segue o jogo; senão, propaga.
473
491
  */
474
- if (!(await tableExists(conn, def.name)))
492
+ if (!(await tableExists(conn, table)))
475
493
  throw error;
476
494
  }
477
495
  }
478
496
  for (const [column, add] of Object.entries(def.columns)) {
479
- if (await columnExists(conn, def.name, column))
497
+ if (await columnExists(conn, table, column))
480
498
  continue;
481
- await conn.schema.alterTable(def.name, (t) => add(t));
499
+ await ddl(conn, loc).alterTable(def.name, (t) => add(t));
482
500
  if (!report.altered[def.name])
483
501
  report.altered[def.name] = [];
484
502
  report.altered[def.name].push(column);
485
503
  }
486
504
  for (const index of def.indexes ?? []) {
487
- if (!(await ensureIndex(conn, def.name, index)))
505
+ if (!(await ensureIndex(conn, loc, def.name, index)))
488
506
  continue;
489
507
  if (!report.indexed)
490
508
  report.indexed = {};
@@ -494,22 +512,26 @@ async function ensureTables(conn, tables, report) {
494
512
  }
495
513
  }
496
514
  }
515
+ function resolveLocation(options) {
516
+ return {
517
+ connection: options.connection,
518
+ schema: validateSchemaName(options.schema, 'schema'),
519
+ };
520
+ }
497
521
  /**
498
522
  * Garante tabelas lib-owned no formato {@link AuthkitTable} — o que `ensureAuthkitSchema` faz com as
499
523
  * do authkit: cria as que faltam, adiciona colunas e índices novos, nunca dropa nem altera. Para
500
524
  * uma extension expor o próprio `ensure*Schema()` para migrations do host. Estável no 1.x.
501
525
  */
502
526
  export async function ensureAuthkitTables(db, tables, options = {}) {
503
- const conn = typeof db.connection !== 'function'
504
- ? db
505
- : options.connection
506
- ? db.connection(options.connection)
507
- : db.connection();
527
+ const loc = resolveLocation(options);
528
+ const conn = authkitTablesClient(db, loc);
529
+ assertSchemaSupported(conn, loc.schema);
508
530
  const report = {
509
531
  created: [],
510
532
  altered: {},
511
533
  };
512
- await ensureTables(conn, tables, report);
534
+ await ensureTables(conn, loc, tables, report);
513
535
  return report;
514
536
  }
515
537
  /**
@@ -521,17 +543,15 @@ export async function ensureAuthkitTables(db, tables, options = {}) {
521
543
  * (`this.db`, um `QueryClient`/`TransactionClient`, usado como está).
522
544
  */
523
545
  export async function ensureAuthkitSchema(db, options = {}) {
524
- const conn = typeof db.connection !== 'function'
525
- ? db
526
- : options.connection
527
- ? db.connection(options.connection)
528
- : db.connection();
546
+ const loc = resolveLocation(options);
547
+ const conn = authkitTablesClient(db, loc);
548
+ assertSchemaSupported(conn, loc.schema);
529
549
  const report = {
530
550
  created: [],
531
551
  altered: {},
532
552
  loginMethods: { table: options.accountTable ?? 'users', ensured: false },
533
553
  };
534
- await ensureTables(conn, [...TABLES, ...(options.tables ?? [])], report);
554
+ await ensureTables(conn, loc, [...TABLES, ...(options.tables ?? [])], report);
535
555
  // Coluna `login_methods` na tabela da CONTA — a tabela é HOST-owned (não está
536
556
  // em TABLES porque o nome/shape são decisão do app), mas a LIB consome a
537
557
  // coluna (LoginMethodsPreferenceCapability). Alguns deploys de host só migram
@@ -547,11 +567,15 @@ export async function ensureAuthkitSchema(db, options = {}) {
547
567
  // `users` fixo: com a conta em `auth_users` (o nome que o próprio scaffold da
548
568
  // lib usa), o `users` fixo acertava uma tabela qualquer de mesmo nome e a
549
569
  // coluna ia parar no lugar errado sem erro nenhum.
570
+ //
571
+ // A tabela da conta fica na conexão do MODEL da conta, não na das tabelas do
572
+ // authkit (`schema.connection`).
550
573
  const accountTable = options.accountTable ?? 'users';
551
- if (await tableExists(conn, accountTable)) {
574
+ const accountConn = authkitTablesClient(db, { connection: options.accountConnection });
575
+ if (await tableExists(accountConn, accountTable)) {
552
576
  try {
553
- if (!(await columnExists(conn, accountTable, 'login_methods'))) {
554
- await conn.schema.alterTable(accountTable, (t) => {
577
+ if (!(await columnExists(accountConn, accountTable, 'login_methods'))) {
578
+ await accountConn.schema.alterTable(accountTable, (t) => {
555
579
  t.jsonb('login_methods').nullable();
556
580
  });
557
581
  report.altered[accountTable] = ['login_methods'];
@@ -568,7 +592,7 @@ export async function ensureAuthkitSchema(db, options = {}) {
568
592
  * o boot não avisava nada — o silêncio que este bloco existe para acabar.
569
593
  * (Mesma semântica do probe de `createTable` logo acima.)
570
594
  */
571
- if (await columnExists(conn, accountTable, 'login_methods')) {
595
+ if (await columnExists(accountConn, accountTable, 'login_methods')) {
572
596
  report.loginMethods.ensured = true;
573
597
  }
574
598
  else {
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Where AuthKit's OWN tables live (`auth_settings`, `auth_mfa`, `auth_password_history`,
3
+ * the organization tables, `authkit_oidc_payloads`, the personal-agent tables, the
4
+ * `authkit_keystore` of the Lucid keystore, and the tables of agent extensions).
5
+ *
6
+ * The rule: every lib-owned table goes through `schema.connection` of `defineConfig`
7
+ * (default: the primary Lucid connection) and, with `schema.name`, lives in that database
8
+ * schema (MySQL: that database). The app's account table is not lib-owned: it stays on the
9
+ * account model's connection and table (`static connection`/`static table` of the model).
10
+ *
11
+ * The schema is written INTO every statement (`"auth"."auth_settings"`). Never put
12
+ * AuthKit's tables in another schema with a connection `searchPath`: knex sends
13
+ * `SET search_path` on the session, and behind PgBouncer in transaction mode that leaks to
14
+ * other clients' connections.
15
+ */
16
+ export interface AuthkitTablesLocation {
17
+ /** Lucid connection name. `undefined` = the primary connection. */
18
+ connection?: string;
19
+ /** Database schema of the tables (MySQL: the database). `undefined` = the connection's default. */
20
+ schema?: string;
21
+ }
22
+ /** Raised for a `schema.name` the database cannot use. The provider fails the boot with it. */
23
+ export declare class AuthkitSchemaError extends Error {
24
+ constructor(message: string);
25
+ }
26
+ /** Throws {@link AuthkitSchemaError} unless `name` is a plain identifier of at most 63 chars. */
27
+ export declare function validateSchemaName(name: unknown, option?: string): string | undefined;
28
+ /** `schema.table` when a schema is set (knex quotes each part: `"schema"."table"`), else `table`. */
29
+ export declare function authkitTable(location: AuthkitTablesLocation | undefined, table: string): string;
30
+ /**
31
+ * The query client for AuthKit's tables. `db` is the Lucid manager (`Database`) or a
32
+ * client the caller already holds (a migration's `this.db`, a transaction), which is
33
+ * used as is.
34
+ */
35
+ export declare function authkitTablesClient(db: any, location?: AuthkitTablesLocation): any;
36
+ /** The Lucid dialect name of a client or manager (`postgres`, `mysql`, `better-sqlite3`…). */
37
+ export declare function dialectOf(client: any): string | undefined;
38
+ /**
39
+ * Throws {@link AuthkitSchemaError} when `schema` is set on a dialect AuthKit cannot use it on:
40
+ * SQLite (no schemas) and any dialect other than Postgres and MySQL. AuthKit never ignores the
41
+ * option nor falls back to unqualified tables.
42
+ */
43
+ export declare function assertSchemaSupported(client: any, schema: string | undefined): void;
44
+ /**
45
+ * `CREATE SCHEMA IF NOT EXISTS` (Postgres) / `CREATE DATABASE IF NOT EXISTS` (MySQL). A role
46
+ * that cannot create it gets an {@link AuthkitSchemaError} naming the schema and the grant.
47
+ */
48
+ export declare function createDbSchema(client: any, schema: string): Promise<void>;
49
+ /**
50
+ * Hidden hook a store built by `lucidAccountStore` exposes so `defineConfig` can tell it
51
+ * where AuthKit's tables live (the store is built before `defineConfig` sees the `schema`
52
+ * option). Not part of the `AccountStore` contract.
53
+ */
54
+ export declare const BIND_TABLES_LOCATION: unique symbol;
55
+ /** Hands `location` to a store that accepts it (see {@link BIND_TABLES_LOCATION}). */
56
+ export declare function bindTablesLocation(store: unknown, location: AuthkitTablesLocation): void;
@@ -0,0 +1,86 @@
1
+ /** Raised for a `schema.name` the database cannot use. The provider fails the boot with it. */
2
+ export class AuthkitSchemaError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = 'AuthkitSchemaError';
6
+ }
7
+ }
8
+ const SCHEMA_NAME = /^[A-Za-z_][A-Za-z0-9_$]*$/;
9
+ /** Throws {@link AuthkitSchemaError} unless `name` is a plain identifier of at most 63 chars. */
10
+ export function validateSchemaName(name, option = 'schema.name') {
11
+ if (name === undefined)
12
+ return undefined;
13
+ if (typeof name !== 'string' || name.length > 63 || !SCHEMA_NAME.test(name)) {
14
+ throw new AuthkitSchemaError(`authkit: ${option} must match /^[A-Za-z_][A-Za-z0-9_$]*$/ and have at most 63 characters (got ${JSON.stringify(name)})`);
15
+ }
16
+ return name;
17
+ }
18
+ /** `schema.table` when a schema is set (knex quotes each part: `"schema"."table"`), else `table`. */
19
+ export function authkitTable(location, table) {
20
+ return location?.schema ? `${location.schema}.${table}` : table;
21
+ }
22
+ /**
23
+ * The query client for AuthKit's tables. `db` is the Lucid manager (`Database`) or a
24
+ * client the caller already holds (a migration's `this.db`, a transaction), which is
25
+ * used as is.
26
+ */
27
+ export function authkitTablesClient(db, location = {}) {
28
+ if (typeof db?.connection !== 'function')
29
+ return db;
30
+ return location.connection ? db.connection(location.connection) : db.connection();
31
+ }
32
+ const SQLITE_DIALECTS = new Set(['sqlite3', 'better-sqlite3', 'libsql']);
33
+ /** Dialects AuthKit writes and creates schemas on. */
34
+ const SCHEMA_DIALECTS = new Set(['postgres', 'redshift', 'mysql']);
35
+ /** The Lucid dialect name of a client or manager (`postgres`, `mysql`, `better-sqlite3`…). */
36
+ export function dialectOf(client) {
37
+ return client?.dialect?.name;
38
+ }
39
+ /**
40
+ * Throws {@link AuthkitSchemaError} when `schema` is set on a dialect AuthKit cannot use it on:
41
+ * SQLite (no schemas) and any dialect other than Postgres and MySQL. AuthKit never ignores the
42
+ * option nor falls back to unqualified tables.
43
+ */
44
+ export function assertSchemaSupported(client, schema) {
45
+ if (!schema)
46
+ return;
47
+ const dialect = dialectOf(client);
48
+ if (dialect && SCHEMA_DIALECTS.has(dialect))
49
+ return;
50
+ throw new AuthkitSchemaError(dialect && SQLITE_DIALECTS.has(dialect)
51
+ ? `authkit: schema.name "${schema}" is set, but the connection uses ${dialect}, which has no schemas. Remove schema.name or use Postgres or MySQL.`
52
+ : `authkit: schema.name "${schema}" is set, but the connection uses ${dialect ?? 'an unknown dialect'}; schema.name supports Postgres and MySQL. Remove schema.name or use one of them.`);
53
+ }
54
+ /**
55
+ * `CREATE SCHEMA IF NOT EXISTS` (Postgres) / `CREATE DATABASE IF NOT EXISTS` (MySQL). A role
56
+ * that cannot create it gets an {@link AuthkitSchemaError} naming the schema and the grant.
57
+ */
58
+ export async function createDbSchema(client, schema) {
59
+ assertSchemaSupported(client, schema);
60
+ const dialect = dialectOf(client);
61
+ const mysql = dialect === 'mysql';
62
+ const sql = mysql
63
+ ? `create database if not exists \`${schema}\``
64
+ : `create schema if not exists "${schema}"`;
65
+ try {
66
+ await client.rawQuery(sql);
67
+ }
68
+ catch (error) {
69
+ const grant = mysql
70
+ ? `GRANT CREATE ON *.* (or create it: CREATE DATABASE \`${schema}\`)`
71
+ : `GRANT CREATE ON DATABASE <db> TO <role> (or create it: CREATE SCHEMA "${schema}")`;
72
+ throw new AuthkitSchemaError(`authkit: could not create schema "${schema}" (${error?.message ?? error}). The database role needs ${grant}.`);
73
+ }
74
+ }
75
+ /**
76
+ * Hidden hook a store built by `lucidAccountStore` exposes so `defineConfig` can tell it
77
+ * where AuthKit's tables live (the store is built before `defineConfig` sees the `schema`
78
+ * option). Not part of the `AccountStore` contract.
79
+ */
80
+ export const BIND_TABLES_LOCATION = Symbol.for('authkit.bindTablesLocation');
81
+ /** Hands `location` to a store that accepts it (see {@link BIND_TABLES_LOCATION}). */
82
+ export function bindTablesLocation(store, location) {
83
+ const bind = store?.[BIND_TABLES_LOCATION];
84
+ if (typeof bind === 'function')
85
+ bind(location);
86
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adonis-agora/authkit-server",
3
- "version": "1.0.0-rc.10",
3
+ "version": "1.0.0-rc.12",
4
4
  "description": "AdonisJS OIDC/OAuth2 provider (Identity Provider) toolkit: ejectable auth server with sessions, rate-limiting, MFA/TOTP, audit log, federated logout and OpenTelemetry metrics.",
5
5
  "license": "MIT",
6
6
  "author": "dudousxd",
@@ -108,7 +108,7 @@
108
108
  }
109
109
  },
110
110
  "dependencies": {
111
- "@adonis-agora/authkit-core": "1.0.0-rc.1",
111
+ "@adonis-agora/authkit-core": "1.0.0-rc.2",
112
112
  "@simplewebauthn/browser": "14.0.0",
113
113
  "@simplewebauthn/server": "14.1.0",
114
114
  "jose": "6.2.16",
@@ -119,7 +119,7 @@
119
119
  "qrcode": "1.5.4"
120
120
  },
121
121
  "devDependencies": {
122
- "@adonis-agora/authkit-react": "1.0.0-rc.4",
122
+ "@adonis-agora/authkit-react": "1.0.0-rc.5",
123
123
  "@adonis-agora/durable": "0.60.0",
124
124
  "@adonis-agora/telescope": "0.27.1",
125
125
  "@adonisjs/ally": "6.3.2",
@@ -4,7 +4,7 @@ description: >-
4
4
  Set up the @adonis-agora/authkit-server OIDC/OAuth2 Authorization Server (Identity
5
5
  Provider) in an AdonisJS app. Covers `node ace add @adonis-agora/authkit-server`,
6
6
  defineConfig({ issuer, adapter, jwks, ttl, globalRolesClaim, accountStore }) with
7
- adapters.redis({ connection }) vs adapters.database({ connection? }),
7
+ adapters.redis({ connection }) vs adapters.database({ connection?, schema? }),
8
8
  lucidAccountStore(AuthUser), JWKS management ({ source: 'managed' | 'jwks' } or
9
9
  'auto', keystore store file/drive/lucid/redis/hashicorp vaults plus
10
10
  @adonis-agora/authkit-vault-aws/azure/gcp createKeystoreVault add-ons),
@@ -83,12 +83,18 @@ export default authServerConfig
83
83
 
84
84
  `adapter` is where oidc-provider persists grants/tokens/codes: `adapters.redis({
85
85
  connection })` requires `@adonisjs/redis` configured; `adapters.database({
86
- connection? })` uses Lucid and stores artifacts in `authkit_oidc_payloads`, which
87
- `ensureAuthkitSchema` creates on boot (with `schema: { autoManage: false }`, call it
88
- from a migration). The table carries an indexed `account_id` column so per-account
86
+ connection?, schema? })` uses Lucid and stores artifacts in `authkit_oidc_payloads`, which
87
+ `ensureAuthkitSchema` creates on boot (with `schema: { autoManage: false }`, call
88
+ `ensureAuthkitSchema(db)` — or `ensureAuthkitSchema(db, { schema })` when `schema.name`
89
+ is set — from a migration). The `schema` defaults to `schema.name` of `defineConfig`.
90
+ The table carries an indexed `account_id` column so per-account
89
91
  session lookups and revocation stay in SQL; rows with a NULL `account_id` are still
90
- found and get classified on read, so no backfill is needed. Works on Postgres,
91
- MySQL and SQLite; expired rows are pruned every 10 minutes per connection. `accountStore` is the identity contract — `lucidAccountStore(AuthUser)`
92
+ found and get classified on read, so no backfill is needed. Without `schema.name` it
93
+ works on Postgres, MySQL and SQLite; with `schema: { name: 'auth' }` every AuthKit
94
+ table lives in that DB schema (`"auth"."auth_settings"`), the boot creates it
95
+ (`CREATE SCHEMA IF NOT EXISTS`; MySQL: `CREATE DATABASE IF NOT EXISTS`), and SQLite
96
+ fails the boot instead of ignoring the option. Never use `searchPath` for this
97
+ (it leaks across clients behind PgBouncer in transaction mode). Expired rows are pruned every 10 minutes per connection. `accountStore` is the identity contract — `lucidAccountStore(AuthUser)`
92
98
  derives `findAccount`/`verifyCredentials` from your user model.
93
99
 
94
100
  Source: `stubs/config/authkit.stub`, `src/define_config.ts` (`AuthServerConfigInput`),
@@ -112,7 +118,7 @@ blob lives); `{ source: 'jwks', keys }` supplies keys inline.
112
118
 
113
119
  The managed keystore's `store` accepts a path shortcut (`store: 'tmp/keystore.json'`)
114
120
  or `{ driver: ... }`: built-in vaults are `file`, `drive` (a `@adonisjs/drive` disk),
115
- `lucid` (table created on first write), `redis`, and `hashicorp`; for cloud secret
121
+ `lucid` (table created on first write; `schema` overrides, default `schema.name`), `redis`, and `hashicorp`; for cloud secret
116
122
  managers install the add-ons `@adonis-agora/authkit-vault-aws` / `-azure` / `-gcp`
117
123
  and pass their `createKeystoreVault(...)` result as `store` (any object with a
118
124
  `read()` method is accepted). With no `store` at all, keys are ephemeral per boot.