hazo_auth 10.2.0 → 10.2.1
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 +14 -0
- package/SETUP_CHECKLIST.md +8 -3
- package/cli-src/lib/services/google_token_service.ts +25 -4
- package/dist/lib/services/google_token_service.d.ts +18 -0
- package/dist/lib/services/google_token_service.d.ts.map +1 -1
- package/dist/lib/services/google_token_service.js +25 -2
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -54,6 +54,16 @@ HAZO_AUTH_OAUTH_KEY_V1=$(openssl rand -base64 32)
|
|
|
54
54
|
npm install hazo_secure
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
+
```js
|
|
58
|
+
// 4. Add hazo_secure to serverExternalPackages in next.config.mjs / next.config.js
|
|
59
|
+
// so the bundler leaves the literal import("hazo_secure/crypto") as a native
|
|
60
|
+
// external import. Without this, Google sign-in fails with
|
|
61
|
+
// GoogleTokenStorageUnconfigured even when hazo_secure is installed.
|
|
62
|
+
const nextConfig = {
|
|
63
|
+
serverExternalPackages: ["hazo_secure", /* ...existing entries */],
|
|
64
|
+
};
|
|
65
|
+
```
|
|
66
|
+
|
|
57
67
|
**Client Usage:**
|
|
58
68
|
```tsx
|
|
59
69
|
import { requestGoogleScopes } from "hazo_auth/client";
|
|
@@ -1340,6 +1350,10 @@ Google OAuth adds one new dependency:
|
|
|
1340
1350
|
HAZO_AUTH_OAUTH_KEY_V1=$(openssl rand -base64 32)
|
|
1341
1351
|
```
|
|
1342
1352
|
3. Install the optional peer: `npm install hazo_secure`
|
|
1353
|
+
4. Add `hazo_secure` to `serverExternalPackages` in `next.config.mjs` / `next.config.js`. The
|
|
1354
|
+
service loads encryption via a literal `import("hazo_secure/crypto")`; if the bundler inlines
|
|
1355
|
+
`hazo_secure` instead of treating it as an external import, Google sign-in fails with
|
|
1356
|
+
`GoogleTokenStorageUnconfigured` even when the peer is installed and keys are set.
|
|
1343
1357
|
|
|
1344
1358
|
**Usage:**
|
|
1345
1359
|
|
package/SETUP_CHECKLIST.md
CHANGED
|
@@ -13,6 +13,7 @@ const nextConfig = {
|
|
|
13
13
|
serverExternalPackages: [
|
|
14
14
|
"hazo_notify", "argon2",
|
|
15
15
|
"hazo_core", "hazo_config", // required for Next 16 + Turbopack
|
|
16
|
+
"hazo_secure", // required if using Google API token storage (getGoogleToken)
|
|
16
17
|
],
|
|
17
18
|
};
|
|
18
19
|
```
|
|
@@ -1138,13 +1139,17 @@ ls app/api/hazo_auth/set_password/route.ts
|
|
|
1138
1139
|
Only needed if you use `requestGoogleScopes` / `getGoogleToken` for Google API access beyond sign-in:
|
|
1139
1140
|
|
|
1140
1141
|
1. Install optional peer: `npm install hazo_secure`
|
|
1141
|
-
2.
|
|
1142
|
-
|
|
1142
|
+
2. Add `hazo_secure` to `serverExternalPackages` in `next.config.mjs` / `next.config.js`. The
|
|
1143
|
+
service loads encryption via a literal `import("hazo_secure/crypto")`; if the bundler inlines
|
|
1144
|
+
`hazo_secure` rather than leaving it as a native external import, Google sign-in fails with
|
|
1145
|
+
`GoogleTokenStorageUnconfigured` even when the peer is installed and keys are configured.
|
|
1146
|
+
3. Run migration: `npm run migrate -- migrations/021_hazo_google_oauth_tokens.sql`
|
|
1147
|
+
4. Set env vars:
|
|
1143
1148
|
```env
|
|
1144
1149
|
HAZO_AUTH_OAUTH_KEY_CURRENT=v1
|
|
1145
1150
|
HAZO_AUTH_OAUTH_KEY_V1=<base64-32-bytes from: openssl rand -base64 32>
|
|
1146
1151
|
```
|
|
1147
|
-
|
|
1152
|
+
5. Wire the new routes in your Next.js app (same pattern as other hazo_auth routes):
|
|
1148
1153
|
```ts
|
|
1149
1154
|
// app/api/hazo_auth/google/token/route.ts
|
|
1150
1155
|
export { GET as googleTokenGET, DELETE as googleTokenDELETE } from "hazo_auth/server/routes";
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import { createCrudService } from "hazo_connect/server";
|
|
4
4
|
import { get_hazo_connect_instance } from "../hazo_connect_instance.server.js";
|
|
5
5
|
import { create_app_logger } from "../app_logger.js";
|
|
6
|
-
import { optional_import } from "hazo_core";
|
|
7
6
|
import { randomUUID } from "crypto";
|
|
8
7
|
|
|
9
8
|
// section: errors
|
|
@@ -70,10 +69,32 @@ function makeKeyProvider(
|
|
|
70
69
|
});
|
|
71
70
|
}
|
|
72
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Indirection around the hazo_secure/crypto dynamic import.
|
|
74
|
+
*
|
|
75
|
+
* The import specifier MUST be a string literal. hazo_secure is an optional
|
|
76
|
+
* peer dep, so this used to go through hazo_core's `optional_import(pkg)` — but
|
|
77
|
+
* that performs a dynamic `import(variable)`, which Turbopack/webpack cannot
|
|
78
|
+
* statically resolve when consumers bundle their server. The import then fails
|
|
79
|
+
* unconditionally and sign-in dies on GoogleTokenStorageUnconfigured even when
|
|
80
|
+
* hazo_secure is installed. A literal `import("hazo_secure/crypto")` is left as
|
|
81
|
+
* a native external import and resolves at runtime (consumers must list
|
|
82
|
+
* hazo_secure in serverExternalPackages so it isn't bundled).
|
|
83
|
+
*
|
|
84
|
+
* Wrapped in an object so tests can stub `_cryptoLoader.load` without touching
|
|
85
|
+
* the literal specifier. Not part of the public API (underscore-prefixed).
|
|
86
|
+
*/
|
|
87
|
+
export const _cryptoLoader = {
|
|
88
|
+
load: (): Promise<typeof import("hazo_secure/crypto")> => import("hazo_secure/crypto"),
|
|
89
|
+
};
|
|
90
|
+
|
|
73
91
|
async function load_crypto_module() {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
92
|
+
let cryptoModule: typeof import("hazo_secure/crypto") | null;
|
|
93
|
+
try {
|
|
94
|
+
cryptoModule = await _cryptoLoader.load();
|
|
95
|
+
} catch {
|
|
96
|
+
cryptoModule = null;
|
|
97
|
+
}
|
|
77
98
|
if (!cryptoModule) throw new GoogleTokenStorageUnconfigured();
|
|
78
99
|
return cryptoModule;
|
|
79
100
|
}
|
|
@@ -21,6 +21,24 @@ export type GoogleTokenStatus = {
|
|
|
21
21
|
scopes: string;
|
|
22
22
|
expires_at: string | null;
|
|
23
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* Indirection around the hazo_secure/crypto dynamic import.
|
|
26
|
+
*
|
|
27
|
+
* The import specifier MUST be a string literal. hazo_secure is an optional
|
|
28
|
+
* peer dep, so this used to go through hazo_core's `optional_import(pkg)` — but
|
|
29
|
+
* that performs a dynamic `import(variable)`, which Turbopack/webpack cannot
|
|
30
|
+
* statically resolve when consumers bundle their server. The import then fails
|
|
31
|
+
* unconditionally and sign-in dies on GoogleTokenStorageUnconfigured even when
|
|
32
|
+
* hazo_secure is installed. A literal `import("hazo_secure/crypto")` is left as
|
|
33
|
+
* a native external import and resolves at runtime (consumers must list
|
|
34
|
+
* hazo_secure in serverExternalPackages so it isn't bundled).
|
|
35
|
+
*
|
|
36
|
+
* Wrapped in an object so tests can stub `_cryptoLoader.load` without touching
|
|
37
|
+
* the literal specifier. Not part of the public API (underscore-prefixed).
|
|
38
|
+
*/
|
|
39
|
+
export declare const _cryptoLoader: {
|
|
40
|
+
load: () => Promise<typeof import("hazo_secure/crypto")>;
|
|
41
|
+
};
|
|
24
42
|
/**
|
|
25
43
|
* Stores (inserts or updates) Google OAuth tokens for a user, encrypting sensitive fields.
|
|
26
44
|
* Throws GoogleTokenStorageUnconfigured if hazo_secure/crypto is unavailable or keys are missing.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google_token_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/google_token_service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"google_token_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/google_token_service.ts"],"names":[],"mappings":"AASA,qBAAa,8BAA+B,SAAQ,KAAK;;CAOxD;AAID,MAAM,MAAM,2BAA2B,GAAG;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,eAAe,GAAG,oBAAoB,GAAG,gBAAgB,GAAG,cAAc,CAAA;CAAE,CAAC;AAErG,MAAM,MAAM,iBAAiB,GAAG;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAmCF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,aAAa;gBACd,OAAO,CAAC,cAAc,oBAAoB,CAAC,CAAC;CACvD,CAAC;AAeF;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,2BAA2B,GAClC,OAAO,CAAC,IAAI,CAAC,CA0Ef;AAID;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAC3B,OAAO,CAAC,iBAAiB,CAAC,CA6I5B;AAID;;GAEG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6D1C;AAID;;;GAGG;AACH,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAexF"}
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import { createCrudService } from "hazo_connect/server";
|
|
4
4
|
import { get_hazo_connect_instance } from "../hazo_connect_instance.server.js";
|
|
5
5
|
import { create_app_logger } from "../app_logger.js";
|
|
6
|
-
import { optional_import } from "hazo_core";
|
|
7
6
|
import { randomUUID } from "crypto";
|
|
8
7
|
// section: errors
|
|
9
8
|
export class GoogleTokenStorageUnconfigured extends Error {
|
|
@@ -26,8 +25,32 @@ function makeKeyProvider(LookupKeyProvider) {
|
|
|
26
25
|
return undefined;
|
|
27
26
|
});
|
|
28
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Indirection around the hazo_secure/crypto dynamic import.
|
|
30
|
+
*
|
|
31
|
+
* The import specifier MUST be a string literal. hazo_secure is an optional
|
|
32
|
+
* peer dep, so this used to go through hazo_core's `optional_import(pkg)` — but
|
|
33
|
+
* that performs a dynamic `import(variable)`, which Turbopack/webpack cannot
|
|
34
|
+
* statically resolve when consumers bundle their server. The import then fails
|
|
35
|
+
* unconditionally and sign-in dies on GoogleTokenStorageUnconfigured even when
|
|
36
|
+
* hazo_secure is installed. A literal `import("hazo_secure/crypto")` is left as
|
|
37
|
+
* a native external import and resolves at runtime (consumers must list
|
|
38
|
+
* hazo_secure in serverExternalPackages so it isn't bundled).
|
|
39
|
+
*
|
|
40
|
+
* Wrapped in an object so tests can stub `_cryptoLoader.load` without touching
|
|
41
|
+
* the literal specifier. Not part of the public API (underscore-prefixed).
|
|
42
|
+
*/
|
|
43
|
+
export const _cryptoLoader = {
|
|
44
|
+
load: () => import("hazo_secure/crypto"),
|
|
45
|
+
};
|
|
29
46
|
async function load_crypto_module() {
|
|
30
|
-
|
|
47
|
+
let cryptoModule;
|
|
48
|
+
try {
|
|
49
|
+
cryptoModule = await _cryptoLoader.load();
|
|
50
|
+
}
|
|
51
|
+
catch (_a) {
|
|
52
|
+
cryptoModule = null;
|
|
53
|
+
}
|
|
31
54
|
if (!cryptoModule)
|
|
32
55
|
throw new GoogleTokenStorageUnconfigured();
|
|
33
56
|
return cryptoModule;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hazo_auth",
|
|
3
|
-
"version": "10.2.
|
|
3
|
+
"version": "10.2.1",
|
|
4
4
|
"description": "Zero-config authentication UI components for Next.js with RBAC, OAuth, scope-based multi-tenancy, and invitations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"authentication",
|
|
@@ -253,9 +253,9 @@
|
|
|
253
253
|
"@radix-ui/react-tabs": "^1.1.0",
|
|
254
254
|
"@radix-ui/react-tooltip": "^1.2.0",
|
|
255
255
|
"hazo_api": "^2.4.0",
|
|
256
|
-
"hazo_config": "^2.1.
|
|
257
|
-
"hazo_connect": "^3.
|
|
258
|
-
"hazo_core": "^1.
|
|
256
|
+
"hazo_config": "^2.1.11",
|
|
257
|
+
"hazo_connect": "^3.7.0",
|
|
258
|
+
"hazo_core": "^1.2.0",
|
|
259
259
|
"hazo_logs": "^2.0.3",
|
|
260
260
|
"hazo_notify": "^6.1.3",
|
|
261
261
|
"hazo_secure": "^1.1.0",
|
|
@@ -393,9 +393,9 @@
|
|
|
393
393
|
"eslint-config-next": "^16.0.4",
|
|
394
394
|
"eslint-plugin-storybook": "^10.0.6",
|
|
395
395
|
"hazo_api": "^2.4.0",
|
|
396
|
-
"hazo_config": "^2.1.
|
|
397
|
-
"hazo_connect": "^3.
|
|
398
|
-
"hazo_core": "^1.
|
|
396
|
+
"hazo_config": "^2.1.11",
|
|
397
|
+
"hazo_connect": "^3.7.0",
|
|
398
|
+
"hazo_core": "^1.2.0",
|
|
399
399
|
"hazo_logs": "^2.0.3",
|
|
400
400
|
"hazo_notify": "^6.1.3",
|
|
401
401
|
"hazo_ui": "^4.0.0",
|