@growth-labs/auth 0.3.5 → 0.3.6
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 +12 -10
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +7 -9
- package/dist/middleware/auth.js.map +1 -1
- package/dist/types.d.ts +8 -11
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/tokens.d.ts +1 -1
- package/dist/utils/tokens.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,8 +41,8 @@ auth({
|
|
|
41
41
|
1. Reads `{cookiePrefix}_at` and `{cookiePrefix}_rt` cookies
|
|
42
42
|
2. Verifies access token JWT against issuer's JWKS (`{issuer}/.well-known/jwks.json`, cached in Worker memory)
|
|
43
43
|
3. If expired but refresh token valid → silent refresh, set new cookies
|
|
44
|
-
4. Populates `context.locals.user` as `
|
|
45
|
-
5. If path matches `gatedPaths` and user
|
|
44
|
+
4. Populates `context.locals.user` as `User | null`
|
|
45
|
+
5. If path matches `gatedPaths` and `user` is null → redirect to `loginPath`
|
|
46
46
|
|
|
47
47
|
**Routes:**
|
|
48
48
|
- `GET /login` — provider-selection page; `?provider=google|password|email-code` starts auth locally and redirects into the issuer's generic `/authorize` endpoint
|
|
@@ -67,10 +67,10 @@ If a renderer is omitted, the current default behavior is unchanged.
|
|
|
67
67
|
```typescript
|
|
68
68
|
// Gated page — user guaranteed authenticated
|
|
69
69
|
const { user } = Astro.locals
|
|
70
|
-
// user.id, user.email, user.name, user.
|
|
70
|
+
// user.id, user.email, user.name, user.avatarUrl
|
|
71
71
|
|
|
72
72
|
// Non-gated page — check first
|
|
73
|
-
if (user
|
|
73
|
+
if (user) {
|
|
74
74
|
// show personalized content
|
|
75
75
|
}
|
|
76
76
|
```
|
|
@@ -78,12 +78,14 @@ if (user.authenticated) {
|
|
|
78
78
|
## TypeScript
|
|
79
79
|
|
|
80
80
|
```typescript
|
|
81
|
-
interface
|
|
82
|
-
id: string
|
|
81
|
+
interface User {
|
|
82
|
+
id: string
|
|
83
|
+
email: string
|
|
84
|
+
name?: string | null
|
|
85
|
+
avatarUrl?: string | null
|
|
83
86
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
// Available on context.locals.user (Astro.locals.user in .astro files)
|
|
87
|
+
|
|
88
|
+
// Available as User | null on context.locals.user (Astro.locals.user in .astro files)
|
|
87
89
|
```
|
|
88
90
|
|
|
89
91
|
## Wrangler Bindings
|
|
@@ -101,7 +103,7 @@ Auth middleware MUST run before consent and analytics middleware. List `auth()`
|
|
|
101
103
|
## Issuer Unreachable (Cold Start)
|
|
102
104
|
|
|
103
105
|
JWKS cached in Worker memory. If issuer unreachable on cold start:
|
|
104
|
-
- **Non-gated paths:** fail open — `user =
|
|
106
|
+
- **Non-gated paths:** fail open — `user = null`, page serves normally
|
|
105
107
|
- **Gated paths:** fail closed — redirect to loginPath
|
|
106
108
|
|
|
107
109
|
There is no public runtime/admin API for evicting the JWKS cache. Cache
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAKA,wBAAsB,SAAS,CAC9B,OAAO,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,GAAG,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EACxE,IAAI,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,GAC3B,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAKA,wBAAsB,SAAS,CAC9B,OAAO,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,GAAG,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,EACxE,IAAI,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,GAC3B,OAAO,CAAC,QAAQ,CAAC,CAgEnB"}
|
package/dist/middleware/auth.js
CHANGED
|
@@ -8,7 +8,7 @@ export async function onRequest(context, next) {
|
|
|
8
8
|
const accessToken = getCookie(request, `${options.cookiePrefix}_at`);
|
|
9
9
|
const refreshToken = getCookie(request, `${options.cookiePrefix}_rt`);
|
|
10
10
|
// 2. Attempt to authenticate
|
|
11
|
-
let user =
|
|
11
|
+
let user = null;
|
|
12
12
|
let refreshed = null;
|
|
13
13
|
if (accessToken) {
|
|
14
14
|
const verified = await verifyAccessToken(options.issuer, accessToken);
|
|
@@ -16,29 +16,27 @@ export async function onRequest(context, next) {
|
|
|
16
16
|
user = {
|
|
17
17
|
id: verified.sub,
|
|
18
18
|
email: verified.email,
|
|
19
|
-
name: verified.name,
|
|
20
|
-
|
|
21
|
-
authenticated: true,
|
|
19
|
+
name: verified.name ?? null,
|
|
20
|
+
avatarUrl: verified.image ?? null,
|
|
22
21
|
};
|
|
23
22
|
}
|
|
24
23
|
}
|
|
25
|
-
if (!user
|
|
24
|
+
if (!user && refreshToken) {
|
|
26
25
|
const clientId = options.clientId || context.url.hostname;
|
|
27
26
|
refreshed = await refreshTokens(options.issuer, refreshToken, clientId);
|
|
28
27
|
if (refreshed) {
|
|
29
28
|
user = {
|
|
30
29
|
id: refreshed.claims.sub,
|
|
31
30
|
email: refreshed.claims.email,
|
|
32
|
-
name: refreshed.claims.name,
|
|
33
|
-
|
|
34
|
-
authenticated: true,
|
|
31
|
+
name: refreshed.claims.name ?? null,
|
|
32
|
+
avatarUrl: refreshed.claims.image ?? null,
|
|
35
33
|
};
|
|
36
34
|
}
|
|
37
35
|
}
|
|
38
36
|
// 3. Populate context.locals.user
|
|
39
37
|
context.locals.user = user;
|
|
40
38
|
// 4. Gate protected paths
|
|
41
|
-
if (!user
|
|
39
|
+
if (!user && isGatedPath(context.url.pathname, options.gatedPaths)) {
|
|
42
40
|
const loginUrl = new URL(`${options.loginPath}?redirect=${encodeURIComponent(context.url.pathname)}`, context.url.origin);
|
|
43
41
|
return Response.redirect(loginUrl.toString(), 302);
|
|
44
42
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAE9C,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAChE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAErE,MAAM,CAAC,KAAK,UAAU,SAAS,CAC9B,OAAwE,EACxE,IAA6B;IAE7B,MAAM,OAAO,GAAG,SAAS,EAAE,CAAA;IAC3B,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;IAE3B,8BAA8B;IAC9B,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,YAAY,KAAK,CAAC,CAAA;IACpE,MAAM,YAAY,GAAG,SAAS,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,YAAY,KAAK,CAAC,CAAA;IAErE,6BAA6B;IAC7B,IAAI,IAAI,
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface User {
|
|
2
2
|
id: string;
|
|
3
3
|
email: string;
|
|
4
|
-
name?: string;
|
|
5
|
-
|
|
6
|
-
authenticated: true;
|
|
4
|
+
name?: string | null;
|
|
5
|
+
avatarUrl?: string | null;
|
|
7
6
|
}
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
export type User = AuthenticatedUser | UnauthenticatedUser;
|
|
7
|
+
export type AuthenticatedUser = User;
|
|
8
|
+
export type UnauthenticatedUser = null;
|
|
12
9
|
export interface AuthRendererBrand {
|
|
13
10
|
title: string;
|
|
14
11
|
brandName: string;
|
|
@@ -60,7 +57,7 @@ export interface TokenRefreshResult {
|
|
|
60
57
|
claims: {
|
|
61
58
|
sub: string;
|
|
62
59
|
email: string;
|
|
63
|
-
name?: string;
|
|
60
|
+
name?: string | null;
|
|
64
61
|
image?: string;
|
|
65
62
|
};
|
|
66
63
|
}
|
|
@@ -72,14 +69,14 @@ export interface TokenExchangeResult {
|
|
|
72
69
|
claims: {
|
|
73
70
|
sub: string;
|
|
74
71
|
email: string;
|
|
75
|
-
name?: string;
|
|
72
|
+
name?: string | null;
|
|
76
73
|
image?: string;
|
|
77
74
|
};
|
|
78
75
|
}
|
|
79
76
|
declare global {
|
|
80
77
|
namespace App {
|
|
81
78
|
interface Locals {
|
|
82
|
-
user: User;
|
|
79
|
+
user: User | null;
|
|
83
80
|
}
|
|
84
81
|
}
|
|
85
82
|
}
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/tokens.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/utils/tokens.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAkBrD,MAAM,WAAW,cAAc;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/utils/tokens.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAkBrD,MAAM,WAAW,cAAc;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,kBAAmB,SAAQ,cAAc;IACzD,SAAS,EAAE,OAAO,CAAA;CAClB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,kBAAkB,CAWvF;AAED,wBAAsB,iBAAiB,CACtC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAehC;AAED,wBAAsB,aAAa,CAClC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAoCpC;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMrE;AAED,6EAA6E;AAC7E,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
|