@ingram-tech/nk-auth 0.11.1 → 0.12.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/README.md +20 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/keys.d.ts +15 -0
- package/dist/keys.d.ts.map +1 -1
- package/dist/keys.js +36 -4
- package/dist/keys.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ exactly one Better Auth copy in the app.
|
|
|
11
11
|
|
|
12
12
|
| Export (subpath) | For |
|
|
13
13
|
| --- | --- |
|
|
14
|
+
| `authEnv`, `authSecret`, `isConfigured` (`./`) | env validation — `authEnv()` returns the full `{ secret, baseURL, databaseUrl }` bundle; `authSecret()` resolves just the secret (with the prod/dev rule) for sites that derive their own `baseURL` / DB connection |
|
|
14
15
|
| `backendJwtOptions` / `verifyBackendJwt` (`./jwt`) | a JWT for the site's own backend API (custom `audience`) |
|
|
15
16
|
| `nkOrganizationDefaults`, `lastActiveOrganizationHooks`, `lastActiveOrganizationUserField` (`./organization`) | org-plugin defaults + active-org restore/persist |
|
|
16
17
|
| `createAuthPool` (`./pool`) | **deprecated** — alias of `createPool` from [`@ingram-tech/nk-db`](../nk-db); inject the site's shared pool instead |
|
|
@@ -29,10 +30,6 @@ exactly one Better Auth copy in the app.
|
|
|
29
30
|
> `nkOrganizationDefaults`, and `lastActiveOrganizationHooks(pool)` in your
|
|
30
31
|
> `betterAuth()`; verify backend tokens with `verifyBackendJwt`. Keep
|
|
31
32
|
> app-specific bits (SSO restrictions, permissions/roles, connectors) in the app.
|
|
32
|
-
>
|
|
33
|
-
> **Note:** pin `kysely@0.28.x` in the consuming app (0.29 moved
|
|
34
|
-
> `DEFAULT_MIGRATION_TABLE` out of its barrel, breaking the adapter + the
|
|
35
|
-
> Turbopack build).
|
|
36
33
|
|
|
37
34
|
## Install
|
|
38
35
|
|
|
@@ -52,6 +49,25 @@ Outside production, `BETTER_AUTH_SECRET` falls back to a well-known insecure
|
|
|
52
49
|
placeholder, so local dev and tests run without setting it (a warning is logged).
|
|
53
50
|
In production it stays required — a missing secret throws at startup.
|
|
54
51
|
|
|
52
|
+
If your site derives its own `baseURL` and opens its own database connection, it
|
|
53
|
+
may not want `authEnv()`'s all-or-nothing bundle (which also requires
|
|
54
|
+
`BETTER_AUTH_URL` and `DATABASE_URL`). Take just the secret — same prod/dev rule —
|
|
55
|
+
with `authSecret()`:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { authSecret } from "@ingram-tech/nk-auth";
|
|
59
|
+
|
|
60
|
+
export const auth = betterAuth({
|
|
61
|
+
database: myOwnDirectPool,
|
|
62
|
+
secret: authSecret(), // required in prod, dev placeholder otherwise — owned here
|
|
63
|
+
baseURL: myOwnBaseUrl,
|
|
64
|
+
// ...
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Do this instead of re-implementing the prod-required / dev-placeholder rule in
|
|
69
|
+
the app: the security-sensitive default then lives in exactly one place.
|
|
70
|
+
|
|
55
71
|
## 1. Apply the schema
|
|
56
72
|
|
|
57
73
|
```bash
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { type BackendJwtConfig, backendJwtOptions, verifyBackendJwt } from "./jwt.js";
|
|
2
2
|
export { base58Id, fromPrefixedId, toPrefixedId, uuidGenerateId } from "./id.js";
|
|
3
|
-
export { type AuthEnv, authEnv, isConfigured } from "./keys.js";
|
|
3
|
+
export { type AuthEnv, authEnv, authSecret, isConfigured } from "./keys.js";
|
|
4
4
|
export { bcryptPassword, makeEmailSenders, makePasskeyOptions, type PasskeyConfig, passkeyOptionsForBaseUrl, type SendEmail, } from "./options.js";
|
|
5
5
|
export { lastActiveOrganizationHooks, lastActiveOrganizationUserField, nkOrganizationDefaults, } from "./organization.js";
|
|
6
6
|
export { CREDENTIAL_PROVIDER_ID, DEFAULT_MAX_PASSWORD_LENGTH, DEFAULT_MIN_PASSWORD_LENGTH, type PasswordPolicy, passwordSchema, type ResetPasswordError, type ResetPasswordErrorCode, validateNewPassword, } from "./password.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACtF,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACjF,OAAO,EAAE,KAAK,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACtF,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACjF,OAAO,EAAE,KAAK,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EACN,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,KAAK,aAAa,EAClB,wBAAwB,EACxB,KAAK,SAAS,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EACN,2BAA2B,EAC3B,+BAA+B,EAC/B,sBAAsB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACN,sBAAsB,EACtB,2BAA2B,EAC3B,2BAA2B,EAC3B,KAAK,cAAc,EACnB,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,mBAAmB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// only what it needs (e.g. avoid bcrypt when it doesn't use passwords).
|
|
5
5
|
export { backendJwtOptions, verifyBackendJwt } from "./jwt.js";
|
|
6
6
|
export { base58Id, fromPrefixedId, toPrefixedId, uuidGenerateId } from "./id.js";
|
|
7
|
-
export { authEnv, isConfigured } from "./keys.js";
|
|
7
|
+
export { authEnv, authSecret, isConfigured } from "./keys.js";
|
|
8
8
|
export { bcryptPassword, makeEmailSenders, makePasskeyOptions, passkeyOptionsForBaseUrl, } from "./options.js";
|
|
9
9
|
export { lastActiveOrganizationHooks, lastActiveOrganizationUserField, nkOrganizationDefaults, } from "./organization.js";
|
|
10
10
|
export { CREDENTIAL_PROVIDER_ID, DEFAULT_MAX_PASSWORD_LENGTH, DEFAULT_MIN_PASSWORD_LENGTH, passwordSchema, validateNewPassword, } from "./password.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,+EAA+E;AAC/E,4EAA4E;AAC5E,wEAAwE;AAExE,OAAO,EAAyB,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACtF,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACjF,OAAO,EAAgB,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,+EAA+E;AAC/E,4EAA4E;AAC5E,wEAAwE;AAExE,OAAO,EAAyB,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACtF,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACjF,OAAO,EAAgB,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EACN,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAElB,wBAAwB,GAExB,MAAM,cAAc,CAAC;AACtB,OAAO,EACN,2BAA2B,EAC3B,+BAA+B,EAC/B,sBAAsB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACN,sBAAsB,EACtB,2BAA2B,EAC3B,2BAA2B,EAE3B,cAAc,EAGd,mBAAmB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/keys.d.ts
CHANGED
|
@@ -16,7 +16,22 @@
|
|
|
16
16
|
* plain `next dev` alike). In production it stays strictly required — a missing
|
|
17
17
|
* secret throws at startup rather than silently signing sessions with a value
|
|
18
18
|
* anyone could guess.
|
|
19
|
+
*
|
|
20
|
+
* Sites that derive their own `baseURL` / database connection can take just the
|
|
21
|
+
* secret's prod/dev rule via `authSecret()` instead of the whole `authEnv()`
|
|
22
|
+
* bundle — so that security-sensitive default is never re-implemented app-side.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Resolve just the session-signing secret, applying the same rule `authEnv()`
|
|
26
|
+
* does: strictly required in production, an insecure dev placeholder otherwise.
|
|
27
|
+
*
|
|
28
|
+
* For sites that derive their own `baseURL` and open their own database
|
|
29
|
+
* connection (so they don't want `authEnv()`'s all-or-nothing bundle) but still
|
|
30
|
+
* want nk-auth to own the secret's prod/dev fallback. Reaching for this keeps
|
|
31
|
+
* the security-sensitive default in one place instead of hand-copied into the
|
|
32
|
+
* app. Backed by the same `secretField()` schema as `authEnv()`.
|
|
19
33
|
*/
|
|
34
|
+
export declare const authSecret: () => string;
|
|
20
35
|
export interface AuthEnv {
|
|
21
36
|
secret: string;
|
|
22
37
|
baseURL: string;
|
package/dist/keys.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AA2CH;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,QAAO,MAW7B,CAAC;AAEF,MAAM,WAAW,OAAO;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,eAAO,MAAM,OAAO,QAAO,OAe1B,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,YAAY,QAAO,OAAuD,CAAC"}
|
package/dist/keys.js
CHANGED
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
* plain `next dev` alike). In production it stays strictly required — a missing
|
|
17
17
|
* secret throws at startup rather than silently signing sessions with a value
|
|
18
18
|
* anyone could guess.
|
|
19
|
+
*
|
|
20
|
+
* Sites that derive their own `baseURL` / database connection can take just the
|
|
21
|
+
* secret's prod/dev rule via `authSecret()` instead of the whole `authEnv()`
|
|
22
|
+
* bundle — so that security-sensitive default is never re-implemented app-side.
|
|
19
23
|
*/
|
|
20
24
|
import { z } from "zod";
|
|
21
25
|
/**
|
|
@@ -37,6 +41,37 @@ const buildSchema = () => z.object({
|
|
|
37
41
|
DATABASE_URL: z.string().min(1),
|
|
38
42
|
});
|
|
39
43
|
let warnedPlaceholder = false;
|
|
44
|
+
/**
|
|
45
|
+
* Warn once when the insecure dev placeholder is in use, so a missing secret is
|
|
46
|
+
* visible in local logs without nagging on every call. Never fires in
|
|
47
|
+
* production, where `secretField()` makes the secret required.
|
|
48
|
+
*/
|
|
49
|
+
const warnIfPlaceholder = (secret) => {
|
|
50
|
+
if (secret === DEV_SECRET_PLACEHOLDER && !warnedPlaceholder) {
|
|
51
|
+
warnedPlaceholder = true;
|
|
52
|
+
console.warn("@ingram-tech/nk-auth: BETTER_AUTH_SECRET is unset — using an insecure dev placeholder. Set it before deploying.");
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Resolve just the session-signing secret, applying the same rule `authEnv()`
|
|
57
|
+
* does: strictly required in production, an insecure dev placeholder otherwise.
|
|
58
|
+
*
|
|
59
|
+
* For sites that derive their own `baseURL` and open their own database
|
|
60
|
+
* connection (so they don't want `authEnv()`'s all-or-nothing bundle) but still
|
|
61
|
+
* want nk-auth to own the secret's prod/dev fallback. Reaching for this keeps
|
|
62
|
+
* the security-sensitive default in one place instead of hand-copied into the
|
|
63
|
+
* app. Backed by the same `secretField()` schema as `authEnv()`.
|
|
64
|
+
*/
|
|
65
|
+
export const authSecret = () => {
|
|
66
|
+
const result = secretField().safeParse(process.env.BETTER_AUTH_SECRET);
|
|
67
|
+
if (!result.success) {
|
|
68
|
+
// secretField() only rejects a missing/empty secret in production (dev
|
|
69
|
+
// supplies the placeholder default), so that is the sole failure here.
|
|
70
|
+
throw new Error("@ingram-tech/nk-auth: BETTER_AUTH_SECRET is required (an unset secret is only allowed outside production)");
|
|
71
|
+
}
|
|
72
|
+
warnIfPlaceholder(result.data);
|
|
73
|
+
return result.data;
|
|
74
|
+
};
|
|
40
75
|
/**
|
|
41
76
|
* Read and validate all nk-auth env vars at once. Throws a single error listing
|
|
42
77
|
* everything missing/invalid, so a misconfigured site fails fast at startup
|
|
@@ -51,10 +86,7 @@ export const authEnv = () => {
|
|
|
51
86
|
throw new Error(`@ingram-tech/nk-auth: invalid environment — ${issues}`);
|
|
52
87
|
}
|
|
53
88
|
const env = result.data;
|
|
54
|
-
|
|
55
|
-
warnedPlaceholder = true;
|
|
56
|
-
console.warn("@ingram-tech/nk-auth: BETTER_AUTH_SECRET is unset — using an insecure dev placeholder. Set it before deploying.");
|
|
57
|
-
}
|
|
89
|
+
warnIfPlaceholder(env.BETTER_AUTH_SECRET);
|
|
58
90
|
return {
|
|
59
91
|
secret: env.BETTER_AUTH_SECRET,
|
|
60
92
|
baseURL: env.BETTER_AUTH_URL,
|
package/dist/keys.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,MAAM,sBAAsB,GAAG,gDAAgD,CAAC;AAEhF;;;;GAIG;AACH,MAAM,WAAW,GAAG,GAAG,EAAE,CACxB,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;IACpC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACnB,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;AAEtD,MAAM,WAAW,GAAG,GAAG,EAAE,CACxB,CAAC,CAAC,MAAM,CAAC;IACR,kBAAkB,EAAE,WAAW,EAAE;IACjC,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACjC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CAC/B,CAAC,CAAC;AAEJ,IAAI,iBAAiB,GAAG,KAAK,CAAC;AAE9B;;;;GAIG;AACH,MAAM,iBAAiB,GAAG,CAAC,MAAc,EAAQ,EAAE;IAClD,IAAI,MAAM,KAAK,sBAAsB,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC7D,iBAAiB,GAAG,IAAI,CAAC;QACzB,OAAO,CAAC,IAAI,CACX,iHAAiH,CACjH,CAAC;IACH,CAAC;AACF,CAAC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,GAAW,EAAE;IACtC,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IACvE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACrB,uEAAuE;QACvE,uEAAuE;QACvE,MAAM,IAAI,KAAK,CACd,2GAA2G,CAC3G,CAAC;IACH,CAAC;IACD,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/B,OAAO,MAAM,CAAC,IAAI,CAAC;AACpB,CAAC,CAAC;AAQF;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,GAAY,EAAE;IACpC,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM;aAChC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;aAC3D,IAAI,CAAC,IAAI,CAAC,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,+CAA+C,MAAM,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC;IACxB,iBAAiB,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAC1C,OAAO;QACN,MAAM,EAAE,GAAG,CAAC,kBAAkB;QAC9B,OAAO,EAAE,GAAG,CAAC,eAAe;QAC5B,WAAW,EAAE,GAAG,CAAC,YAAY;KAC7B,CAAC;AACH,CAAC,CAAC;AAEF,+EAA+E;AAC/E,MAAM,CAAC,MAAM,YAAY,GAAG,GAAY,EAAE,CAAC,WAAW,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ingram-tech/nk-auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "The Ingram Better Auth foundation: composable presets (org, dual-shape JWT, active-org hooks, pg pool) for Next.js sites.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -71,8 +71,8 @@
|
|
|
71
71
|
"zod": "^4.4.3"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
|
74
|
-
"@better-auth/passkey": "^1.6.
|
|
75
|
-
"better-auth": "^1.6.
|
|
74
|
+
"@better-auth/passkey": "^1.6.15",
|
|
75
|
+
"better-auth": "^1.6.15",
|
|
76
76
|
"next": "^15.0.0 || ^16.0.0",
|
|
77
77
|
"pg": "^8.13.0",
|
|
78
78
|
"react": "^18.0.0 || ^19.0.0"
|