@absolutejs/auth 0.78.0 → 0.80.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/CHANGELOG.md ADDED
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@absolutejs/auth`.
4
+
5
+ This file is generated by `absolute-changelog` from the entries in
6
+ `changelog/`. Edit an entry, not this file — and add new ones under
7
+ `changelog/unreleased/`.
8
+
9
+ ## 0.80.0 — 2026-09-22
10
+
11
+ ### Added
12
+
13
+ - **Support existing Drizzle PostgreSQL clients for durable auth sessions** (`createPostgresAuthSessionStore`)
14
+
15
+ ### Fixed
16
+
17
+ - **Run auth setup according to the selected session store instead of always requiring PostgreSQL**
18
+
19
+ ## 0.79.0 — 2026-09-10
20
+
21
+ ### Breaking
22
+
23
+ - **Separate API credential token routes from OIDC and reject conflicting configuration** (`apiKeysRoutes`, `auth`, `createAuthApplications`, `AuthConfig`, `ApiKeysConfig`)
24
+ _Migration:_ Send client_credentials requests to /auth/api/token instead of /oauth2/token and update advertised enterprise token URLs. Keep authorization_code and refresh_token requests at /oauth2/token. Prefer auth({ oidc, apikeys }) for configuration validation. API-only consumers may explicitly keep tokenRoute: /oauth2/token if no OIDC handler uses that path.
package/README.md CHANGED
@@ -392,3 +392,51 @@ using it has expired; duplicate key IDs fail closed.
392
392
  ## Note
393
393
 
394
394
  This project uses Bun and is built for Elysia.
395
+
396
+ ## OAuth and API credential token routes
397
+
398
+ As of 0.79.0, `apiKeysRoutes()` and `auth({ apikeys })` serve the
399
+ `client_credentials` grant at `/auth/api/token` by default. OIDC authorization
400
+ code and refresh grants continue to use `/oauth2/token`. This keeps separately
401
+ mounted plugins from replacing each other's token handler.
402
+
403
+ Update enterprise integrations and displayed token URLs to `/auth/api/token`.
404
+ API-only applications can retain the previous URL by explicitly setting
405
+ `apikeys.tokenRoute: '/oauth2/token'`, provided no OIDC handler uses that path.
406
+
407
+ Prefer configuring both features in `auth({ oidc, apikeys })`: conflicting token
408
+ paths are rejected during construction, including a trailing-slash alias.
409
+ When mounting standalone plugins with custom paths, the consumer must keep
410
+ the paths distinct; Elysia does not reject arbitrary duplicate routes.
411
+
412
+ ### Persistent sessions with an existing PostgreSQL client
413
+
414
+ Use `createPostgresAuthSessionStore(db, decodeUser)` with an existing Drizzle
415
+ PostgreSQL client. It uses the same session tables as the Neon convenience
416
+ adapter; `decodeUser` validates the stored user shape when a session is read.
417
+ Pair it with `createPostgresCredentialStore(db)` for persistent passwords.
418
+ Your application must also persist its own user records.
419
+
420
+ ```ts
421
+ import { SQL } from 'bun';
422
+ import { drizzle } from 'drizzle-orm/bun-sql';
423
+ import { createPostgresAuthSessionStore, createPostgresCredentialStore } from '@absolutejs/auth';
424
+
425
+ const databaseUrl = process.env.DATABASE_URL;
426
+ if (!databaseUrl) throw new Error('DATABASE_URL is required');
427
+ const client = new SQL(databaseUrl);
428
+ const db = drizzle({ client });
429
+ const sessionStore = createPostgresAuthSessionStore(db, decodeUser);
430
+ const credentialStore = createPostgresCredentialStore(db);
431
+ ```
432
+
433
+ Apply the `sessions` and `credentials` migrations before serving requests.
434
+ `runMigrations` accepts a `MigrationClient` for non-Neon PostgreSQL drivers.
435
+ With Bun SQL, use a separate `prepare: false` client for migration scripts,
436
+ and the default prepared-query mode for application queries and JSON columns.
437
+
438
+ Studio's `absolute-auth setup` reads the selected adapter from
439
+ `src/backend/packages/auth.config.ts`. Explicit memory storage skips database
440
+ migrations and warns that sessions reset on restart. The Neon adapter requires
441
+ a real `DATABASE_URL` and runs migrations. Missing or unknown selections fail
442
+ with an actionable error; custom adapters must configure their own migrations.
package/changelog.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "contract": 1,
3
+ "name": "@absolutejs/auth",
4
+ "releases": [
5
+ {
6
+ "changes": [
7
+ {
8
+ "kind": "fixed",
9
+ "summary": "Run auth setup according to the selected session store instead of always requiring PostgreSQL"
10
+ },
11
+ {
12
+ "kind": "added",
13
+ "summary": "Support existing Drizzle PostgreSQL clients for durable auth sessions",
14
+ "symbols": [
15
+ "createPostgresAuthSessionStore"
16
+ ]
17
+ }
18
+ ],
19
+ "date": "2026-09-22",
20
+ "version": "0.80.0"
21
+ },
22
+ {
23
+ "changes": [
24
+ {
25
+ "kind": "breaking",
26
+ "migration": {
27
+ "instruction": "Send client_credentials requests to /auth/api/token instead of /oauth2/token and update advertised enterprise token URLs. Keep authorization_code and refresh_token requests at /oauth2/token. Prefer auth({ oidc, apikeys }) for configuration validation. API-only consumers may explicitly keep tokenRoute: /oauth2/token if no OIDC handler uses that path.",
28
+ "manual": true
29
+ },
30
+ "summary": "Separate API credential token routes from OIDC and reject conflicting configuration",
31
+ "symbols": [
32
+ "apiKeysRoutes",
33
+ "auth",
34
+ "createAuthApplications",
35
+ "AuthConfig",
36
+ "ApiKeysConfig"
37
+ ]
38
+ }
39
+ ],
40
+ "date": "2026-09-10",
41
+ "version": "0.79.0"
42
+ }
43
+ ]
44
+ }
@@ -13,7 +13,7 @@ export type ApiKeysConfig = {
13
13
  /** Static API keys. Used by the exported `verifyApiKey` / `resolveApiPrincipal`
14
14
  * helpers; the consumer wires its own management + guard routes. */
15
15
  apiKeyStore?: ApiKeyStore;
16
- /** Path of the client_credentials token endpoint (defaults to `/oauth2/token`). */
16
+ /** Path of the client_credentials token endpoint (defaults to `/auth/api/token`). */
17
17
  tokenRoute?: RouteString;
18
18
  };
19
19
  export type ClientCredentialsResult = {
@@ -0,0 +1,7 @@
1
+ import type { RouteString } from '../types';
2
+ import { type ApiKeysConfig } from './config';
3
+ /** Elysia replaces duplicate method/path registrations. Refuse that setup
4
+ * before composing the two independently configured token handlers. */
5
+ export declare const assertTokenRouteConfiguration: (apikeys: ApiKeysConfig | undefined, oidc: {
6
+ oidcRoute?: RouteString;
7
+ } | undefined) => void;
@@ -289,6 +289,10 @@ var runImport = async (result, options) => {
289
289
  };
290
290
  };
291
291
 
292
+ // src/cli/setup.ts
293
+ import { resolve } from "path";
294
+ import { pathToFileURL } from "url";
295
+
292
296
  // src/adaptive/postgresStores.ts
293
297
  import { and, desc, eq } from "drizzle-orm";
294
298
  import {
@@ -3473,11 +3477,46 @@ var blockMigrations = {
3473
3477
  webhooks: initMigration("webhooks", [webhookDeliveriesTable])
3474
3478
  };
3475
3479
 
3480
+ // src/cli/setup.ts
3481
+ var readProperty = (value, key) => {
3482
+ const property = typeof value === "object" && value !== null ? Reflect.get(value, key) : undefined;
3483
+ return property;
3484
+ };
3485
+ var setupStorage = (configuration) => {
3486
+ const selected = readProperty(readProperty(configuration, "adapters"), "sessionStore");
3487
+ if (selected === "@absolutejs/auth#createInMemoryAuthSessionStore")
3488
+ return "memory";
3489
+ if (selected === "@absolutejs/auth#createNeonAuthSessionStore")
3490
+ return "neon";
3491
+ throw new Error("Select a supported auth sessionStore adapter in src/backend/packages/auth.config.ts before setup. Custom adapters need their own migrations.");
3492
+ };
3493
+ var loadConfiguration = async () => {
3494
+ const module = await import(pathToFileURL(resolve("src/backend/packages/auth.config.ts")).href);
3495
+ return readProperty(module, "default");
3496
+ };
3497
+ var runSetup = async ({
3498
+ configuration,
3499
+ databaseUrl = process.env["DATABASE_URL"],
3500
+ migrate = runMigrations,
3501
+ log = console.log
3502
+ } = {}) => {
3503
+ const storage = setupStorage(configuration ?? await loadConfiguration());
3504
+ if (storage === "memory") {
3505
+ log("In-memory sessions selected: no database migration is needed. Sign-ins reset on restart; choose persistent storage for a live business.");
3506
+ return { migrated: false, storage };
3507
+ }
3508
+ if (!databaseUrl?.trim())
3509
+ throw new Error("The selected Neon session store requires DATABASE_URL. Configure a real Neon database connection; do not enter a placeholder.");
3510
+ await migrate({ databaseUrl, log });
3511
+ return { migrated: true, storage };
3512
+ };
3513
+
3476
3514
  // src/cli/migrate.ts
3477
3515
  var TOP_USAGE = `Usage:
3478
3516
  bunx absolute-auth <command> [options]
3479
3517
 
3480
3518
  Commands:
3519
+ setup Set up storage selected in the project auth config
3481
3520
  migrate Apply the package's Drizzle migrations
3482
3521
  import <source> <file> Import a user export from another auth library
3483
3522
  <source> is one of: ${Object.keys(importers).sort().join(", ")}
@@ -3647,6 +3686,12 @@ var main = async () => {
3647
3686
  process.stdout.write(TOP_USAGE);
3648
3687
  return;
3649
3688
  }
3689
+ if (command === "setup") {
3690
+ if (argv.length > 0)
3691
+ throw new Error("setup takes no arguments; it reads src/backend/packages/auth.config.ts");
3692
+ await runSetup();
3693
+ return;
3694
+ }
3650
3695
  if (command === "migrate") {
3651
3696
  await runMigrate(argv);
3652
3697
  return;
@@ -3659,5 +3704,5 @@ var main = async () => {
3659
3704
  };
3660
3705
  await main();
3661
3706
 
3662
- //# debugId=1171B72D10FC06DD64756E2164756E21
3707
+ //# debugId=049EB7FB9B6E388E64756E2164756E21
3663
3708
  //# sourceMappingURL=migrate.js.map