bezzie 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 neilpmas
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,202 @@
1
+ # Bezzie
2
+
3
+ **Bezzie** — your BFF's BFF. Handles the Backend for Frontend OAuth pattern so you don't have to.
4
+
5
+ A BFF (Backend for Frontend) OAuth 2.0 auth library for Cloudflare Workers.
6
+
7
+ Implements the [OAuth 2.0 for Browser-Based Apps (BCP212)](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps) pattern — JWTs never touch the browser. The BFF owns the OAuth flow and issues a session cookie to the frontend instead.
8
+
9
+ ```
10
+ npm install bezzie
11
+ ```
12
+
13
+ ---
14
+
15
+ ## Why
16
+
17
+ Most OAuth libraries hand tokens directly to the browser. BCP212 says you shouldn't — it's a significant attack surface. Bezzie keeps tokens server-side in Cloudflare KV and gives the browser a session cookie instead.
18
+
19
+ There's no open source library for this specific combination (BFF OAuth on Cloudflare Workers). The closest alternatives are Duende BFF (.NET) and `@auth0/nextjs-auth0` — both tied to specific frameworks.
20
+
21
+ ---
22
+
23
+ ## Usage
24
+
25
+ ```typescript
26
+ import { createBezzie, providers, cloudflareKV } from 'bezzie'
27
+
28
+ const auth = createBezzie({
29
+ ...providers.auth0('your-tenant.auth0.com'),
30
+ clientId: 'xxx',
31
+ clientSecret: env.AUTH0_CLIENT_SECRET,
32
+ audience: 'https://api.yourproject.com',
33
+ adapter: cloudflareKV(env.SESSION_KV),
34
+ baseUrl: 'https://app.yourproject.com',
35
+ })
36
+
37
+ // Mount auth routes
38
+ app.route('/auth', auth.routes())
39
+
40
+ // Protect API routes
41
+ app.use('/api/*', auth.middleware())
42
+ ```
43
+
44
+ This gives you:
45
+
46
+ | Route | Description |
47
+ |---|---|
48
+ | `GET /auth/login` | Redirects to provider, initiates Authorization Code + PKCE flow. Supports `returnTo` query param for post-login redirect. |
49
+ | `GET /auth/callback` | Exchanges code for tokens, stores session in KV, sets cookie. |
50
+ | `GET /auth/logout` | Clears session, clears cookie, redirects to provider logout. |
51
+
52
+ ---
53
+
54
+ ## Accessing User Identity
55
+
56
+ After `auth.middleware()`, downstream handlers can access the user identity and the current access token via `c.var`:
57
+
58
+ ```typescript
59
+ app.get('/api/me', (c) => {
60
+ const user = c.var.user
61
+ const token = c.var.accessToken
62
+ return c.json({ user })
63
+ })
64
+ ```
65
+
66
+ ## Forwarding Upstream
67
+
68
+ The `accessToken` on the context is intended for the app to forward to an upstream service (e.g., a Spring Boot API or any other microservice), since Bezzie doesn't mutate request headers directly.
69
+
70
+ ```typescript
71
+ app.all('/api/proxy/*', async (c) => {
72
+ const url = new URL(c.req.url)
73
+ const target = `https://api.upstream.com${url.pathname}${url.search}`
74
+
75
+ return fetch(target, {
76
+ method: c.req.method,
77
+ headers: {
78
+ ...c.req.header(),
79
+ 'Authorization': `Bearer ${c.var.accessToken}`
80
+ },
81
+ body: c.req.raw.body
82
+ })
83
+ })
84
+ ```
85
+
86
+ ---
87
+
88
+ ## How It Works
89
+
90
+ ### Login Flow
91
+
92
+ ```
93
+ Browser → BFF /auth/login → Auth0 (Authorization Code + PKCE)
94
+
95
+ code returned
96
+
97
+ BFF exchanges code → tokens stored in KV
98
+ BFF issues HttpOnly session cookie → Browser
99
+ ```
100
+
101
+ ### Per-Request Flow
102
+
103
+ 1. Browser sends request to BFF with session cookie
104
+ 2. BFF looks up session in KV, retrieves access token
105
+ 3. BFF validates JWT (via JWKS, using Web Crypto API)
106
+ 4. If expired, BFF uses refresh token to get a new one and updates KV
107
+ 5. BFF forwards request upstream with `Authorization: Bearer <token>`
108
+
109
+ ### Session Storage
110
+
111
+ Sessions are stored in Cloudflare KV:
112
+
113
+ ```
114
+ sessionId → { accessToken, refreshToken, expiresAt, user }
115
+ ```
116
+
117
+ KV TTL is aligned with the refresh token lifetime. When the refresh token expires, the user must log in again.
118
+
119
+ ---
120
+
121
+ ## Adapters
122
+
123
+ Bezzie supports multiple session storage backends:
124
+
125
+ ### Cloudflare KV
126
+ Recommended for production on Cloudflare Workers.
127
+ ```typescript
128
+ import { cloudflareKV } from 'bezzie'
129
+ // ...
130
+ adapter: cloudflareKV(env.SESSION_KV)
131
+ ```
132
+
133
+ ### Redis (Upstash)
134
+ Good for cross-region session consistency.
135
+ ```typescript
136
+ import { RedisAdapter } from 'bezzie'
137
+ // ...
138
+ adapter: new RedisAdapter({ url: env.REDIS_URL, token: env.REDIS_TOKEN })
139
+ ```
140
+
141
+ ### Memory
142
+ Useful for local development and testing. Do not use in production.
143
+ ```typescript
144
+ import { MemoryAdapter } from 'bezzie'
145
+ // ...
146
+ adapter: new MemoryAdapter()
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Configuration
152
+
153
+ | Option | Type | Description |
154
+ |---|---|---|
155
+ | `issuer` | `string` | Your OIDC provider issuer URL (e.g. `https://tenant.auth0.com`) |
156
+ | `clientId` | `string` | OAuth client ID |
157
+ | `clientSecret` | `string` | OAuth client secret — keep in Workers secrets |
158
+ | `audience` | `string` | API audience identifier |
159
+ | `adapter` | `SessionAdapter` | Session adapter (e.g. `cloudflareKV(env.SESSION_KV)`) |
160
+ | `baseUrl` | `string` | Base URL of your application (used for callback and redirects) |
161
+ | `providerHints` | `object` | Optional tweaks for specific providers (`logoutUrl`, `tokenEndpoint`) |
162
+
163
+ ---
164
+
165
+ ## Cloudflare Setup
166
+
167
+ Add a KV namespace to your `wrangler.toml`:
168
+
169
+ ```toml
170
+ [[kv_namespaces]]
171
+ binding = "SESSION_KV"
172
+ id = "<your-kv-namespace-id>"
173
+ ```
174
+
175
+ Add your client secret as a Workers secret:
176
+
177
+ ```sh
178
+ wrangler secret put AUTH0_CLIENT_SECRET
179
+ ```
180
+
181
+ ---
182
+
183
+ ## Stack
184
+
185
+ | Component | Choice |
186
+ |---|---|
187
+ | Runtime | Cloudflare Workers |
188
+ | Router | Hono |
189
+ | OAuth | `oauth4webapi` (spec-compliant, no Node.js deps) |
190
+ | Session storage | Cloudflare KV |
191
+
192
+ ---
193
+
194
+ ## Status
195
+
196
+ v0.1.0 — pre-release
197
+
198
+ ---
199
+
200
+ ## License
201
+
202
+ MIT
@@ -0,0 +1,10 @@
1
+ import { Session } from '../session';
2
+ import { SessionAdapter, PKCEState } from './types';
3
+ export declare class CloudflareKVAdapter implements SessionAdapter {
4
+ private kv;
5
+ constructor(kv: KVNamespace);
6
+ get(sessionId: string): Promise<Session | PKCEState | null>;
7
+ set(sessionId: string, session: Session | PKCEState, ttlSeconds: number): Promise<void>;
8
+ delete(sessionId: string): Promise<void>;
9
+ }
10
+ //# sourceMappingURL=cloudflare-kv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-kv.d.ts","sourceRoot":"","sources":["../../src/adapters/cloudflare-kv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACpC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAEnD,qBAAa,mBAAoB,YAAW,cAAc;IAC5C,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,WAAW;IAE7B,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;IAK3D,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASvF,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG/C"}
@@ -0,0 +1,22 @@
1
+ export class CloudflareKVAdapter {
2
+ kv;
3
+ constructor(kv) {
4
+ this.kv = kv;
5
+ }
6
+ async get(sessionId) {
7
+ const session = await this.kv.get(sessionId, 'json');
8
+ return session;
9
+ }
10
+ async set(sessionId, session, ttlSeconds) {
11
+ if (ttlSeconds < 60) {
12
+ throw new Error('Bezzie: KV TTL must be at least 60 seconds');
13
+ }
14
+ await this.kv.put(sessionId, JSON.stringify(session), {
15
+ expirationTtl: ttlSeconds,
16
+ });
17
+ }
18
+ async delete(sessionId) {
19
+ await this.kv.delete(sessionId);
20
+ }
21
+ }
22
+ //# sourceMappingURL=cloudflare-kv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-kv.js","sourceRoot":"","sources":["../../src/adapters/cloudflare-kv.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,mBAAmB;IACV;IAApB,YAAoB,EAAe;QAAf,OAAE,GAAF,EAAE,CAAa;IAAG,CAAC;IAEvC,KAAK,CAAC,GAAG,CAAC,SAAiB;QACzB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAsB,SAAS,EAAE,MAAM,CAAC,CAAA;QACzE,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,SAAiB,EAAE,OAA4B,EAAE,UAAkB;QAC3E,IAAI,UAAU,GAAG,EAAE,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;QAC/D,CAAC;QACD,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE;YACpD,aAAa,EAAE,UAAU;SAC1B,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB;QAC5B,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACjC,CAAC;CACF"}
@@ -0,0 +1,5 @@
1
+ export * from './types';
2
+ export * from './cloudflare-kv';
3
+ export * from './redis';
4
+ export * from './memory';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA"}
@@ -0,0 +1,5 @@
1
+ export * from './types';
2
+ export * from './cloudflare-kv';
3
+ export * from './redis';
4
+ export * from './memory';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA"}
@@ -0,0 +1,9 @@
1
+ import { Session } from '../session';
2
+ import { SessionAdapter, PKCEState } from './types';
3
+ export declare class MemoryAdapter implements SessionAdapter {
4
+ private store;
5
+ get(sessionId: string): Promise<Session | PKCEState | null>;
6
+ set(sessionId: string, session: Session | PKCEState, ttlSeconds: number): Promise<void>;
7
+ delete(sessionId: string): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/adapters/memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACpC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAOnD,qBAAa,aAAc,YAAW,cAAc;IAClD,OAAO,CAAC,KAAK,CAAmC;IAE1C,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;IAU3D,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvF,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG/C"}
@@ -0,0 +1,23 @@
1
+ export class MemoryAdapter {
2
+ store = new Map();
3
+ async get(sessionId) {
4
+ const entry = this.store.get(sessionId);
5
+ if (!entry)
6
+ return null;
7
+ if (Date.now() > entry.expiresAt) {
8
+ this.store.delete(sessionId);
9
+ return null;
10
+ }
11
+ return entry.session;
12
+ }
13
+ async set(sessionId, session, ttlSeconds) {
14
+ this.store.set(sessionId, {
15
+ session,
16
+ expiresAt: Date.now() + ttlSeconds * 1000,
17
+ });
18
+ }
19
+ async delete(sessionId) {
20
+ this.store.delete(sessionId);
21
+ }
22
+ }
23
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/adapters/memory.ts"],"names":[],"mappings":"AAQA,MAAM,OAAO,aAAa;IAChB,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAA;IAEhD,KAAK,CAAC,GAAG,CAAC,SAAiB;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACvC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAA;QACvB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;YAC5B,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,KAAK,CAAC,OAAO,CAAA;IACtB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,SAAiB,EAAE,OAA4B,EAAE,UAAkB;QAC3E,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE;YACxB,OAAO;YACP,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI;SAC1C,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB;QAC5B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IAC9B,CAAC;CACF"}
@@ -0,0 +1,17 @@
1
+ import { Session } from '../session';
2
+ import { SessionAdapter, PKCEState } from './types';
3
+ export interface RedisClient {
4
+ get(key: string): Promise<string | null>;
5
+ set(key: string, value: string, options?: {
6
+ ex?: number;
7
+ }): Promise<unknown>;
8
+ del(key: string): Promise<unknown>;
9
+ }
10
+ export declare class RedisAdapter implements SessionAdapter {
11
+ private redis;
12
+ constructor(redis: RedisClient);
13
+ get(sessionId: string): Promise<Session | PKCEState | null>;
14
+ set(sessionId: string, session: Session | PKCEState, ttlSeconds: number): Promise<void>;
15
+ delete(sessionId: string): Promise<void>;
16
+ }
17
+ //# sourceMappingURL=redis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../src/adapters/redis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACpC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAEnD,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IACxC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC5E,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CACnC;AAED,qBAAa,YAAa,YAAW,cAAc;IACrC,OAAO,CAAC,KAAK;gBAAL,KAAK,EAAE,WAAW;IAEhC,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;IAM3D,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvF,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG/C"}
@@ -0,0 +1,19 @@
1
+ export class RedisAdapter {
2
+ redis;
3
+ constructor(redis) {
4
+ this.redis = redis;
5
+ }
6
+ async get(sessionId) {
7
+ const session = await this.redis.get(sessionId);
8
+ if (!session)
9
+ return null;
10
+ return JSON.parse(session);
11
+ }
12
+ async set(sessionId, session, ttlSeconds) {
13
+ await this.redis.set(sessionId, JSON.stringify(session), { ex: ttlSeconds });
14
+ }
15
+ async delete(sessionId) {
16
+ await this.redis.del(sessionId);
17
+ }
18
+ }
19
+ //# sourceMappingURL=redis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis.js","sourceRoot":"","sources":["../../src/adapters/redis.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,YAAY;IACH;IAApB,YAAoB,KAAkB;QAAlB,UAAK,GAAL,KAAK,CAAa;IAAG,CAAC;IAE1C,KAAK,CAAC,GAAG,CAAC,SAAiB;QACzB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC/C,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAA;QACzB,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAwB,CAAA;IACnD,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,SAAiB,EAAE,OAA4B,EAAE,UAAkB;QAC3E,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,CAAA;IAC9E,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB;QAC5B,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IACjC,CAAC;CACF"}
@@ -0,0 +1,41 @@
1
+ import { Session } from '../session';
2
+ /**
3
+ * Temporary state for the PKCE OAuth flow.
4
+ */
5
+ export interface PKCEState {
6
+ /**
7
+ * Code verifier for PKCE.
8
+ */
9
+ codeVerifier: string;
10
+ /**
11
+ * URL to redirect to after successful authentication.
12
+ */
13
+ returnTo?: string;
14
+ }
15
+ /**
16
+ * Interface for session storage adapters.
17
+ */
18
+ export interface SessionAdapter {
19
+ /**
20
+ * Retrieves a session or PKCE state by ID.
21
+ *
22
+ * @param sessionId Session ID
23
+ * @returns Session, PKCE state, or null if not found
24
+ */
25
+ get(sessionId: string): Promise<Session | PKCEState | null>;
26
+ /**
27
+ * Stores a session or PKCE state.
28
+ *
29
+ * @param sessionId Session ID
30
+ * @param session Session or PKCE state
31
+ * @param ttlSeconds Time-to-live in seconds
32
+ */
33
+ set(sessionId: string, session: Session | PKCEState, ttlSeconds: number): Promise<void>;
34
+ /**
35
+ * Deletes a session or PKCE state.
36
+ *
37
+ * @param sessionId Session ID
38
+ */
39
+ delete(sessionId: string): Promise<void>;
40
+ }
41
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEpC;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC,CAAA;IAE3D;;;;;;OAMG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEvF;;;;OAIG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACzC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,109 @@
1
+ import { Hono, type MiddlewareHandler } from 'hono';
2
+ import { type Variables } from './middleware';
3
+ import { type SessionAdapter } from './session';
4
+ /**
5
+ * Configuration for Bezzie.
6
+ */
7
+ export interface BezzieConfig {
8
+ /**
9
+ * Your OIDC provider issuer URL (e.g. `https://tenant.auth0.com`).
10
+ */
11
+ issuer: string;
12
+ /**
13
+ * OAuth client ID.
14
+ */
15
+ clientId: string;
16
+ /**
17
+ * OAuth client secret — keep this in Workers secrets.
18
+ */
19
+ clientSecret: string;
20
+ /**
21
+ * Optional API audience identifier.
22
+ */
23
+ audience?: string;
24
+ /**
25
+ * Session adapter (e.g. `cloudflareKV(env.SESSION_KV)`).
26
+ */
27
+ adapter: SessionAdapter;
28
+ /**
29
+ * Base URL of your application (used for callback and redirects).
30
+ */
31
+ baseUrl: string;
32
+ /**
33
+ * Optional tweaks for specific providers.
34
+ */
35
+ providerHints?: {
36
+ /**
37
+ * Custom logout URL if different from the default OIDC logout.
38
+ */
39
+ logoutUrl?: string;
40
+ /**
41
+ * Custom token endpoint if different from the discovery metadata.
42
+ */
43
+ tokenEndpoint?: string;
44
+ };
45
+ }
46
+ /**
47
+ * Common OIDC provider configurations.
48
+ */
49
+ export declare const providers: {
50
+ /**
51
+ * Auth0 provider configuration.
52
+ */
53
+ auth0: (domain: string) => {
54
+ issuer: string;
55
+ providerHints: {
56
+ logoutUrl: string;
57
+ };
58
+ };
59
+ /**
60
+ * Okta provider configuration.
61
+ */
62
+ okta: (domain: string) => {
63
+ issuer: string;
64
+ };
65
+ /**
66
+ * Keycloak provider configuration.
67
+ */
68
+ keycloak: (baseUrl: string, realm: string) => {
69
+ issuer: string;
70
+ };
71
+ /**
72
+ * Google provider configuration.
73
+ */
74
+ google: () => {
75
+ issuer: string;
76
+ };
77
+ };
78
+ /**
79
+ * Creates a Cloudflare KV session adapter.
80
+ */
81
+ declare function cloudflareKV(kv: KVNamespace): SessionAdapter;
82
+ /**
83
+ * The main Bezzie interface.
84
+ */
85
+ export interface Bezzie {
86
+ /**
87
+ * Returns a Hono app containing the auth routes (/login, /callback, /logout).
88
+ */
89
+ routes: () => Hono;
90
+ /**
91
+ * Returns a Hono middleware that protects routes and manages sessions.
92
+ */
93
+ middleware: () => MiddlewareHandler<{
94
+ Variables: Variables;
95
+ }>;
96
+ }
97
+ /**
98
+ * Creates a new Bezzie instance.
99
+ *
100
+ * @param config Bezzie configuration
101
+ * @returns Bezzie instance
102
+ * @throws {Error} if required configuration is missing or invalid
103
+ */
104
+ declare function createBezzie(config: BezzieConfig): Bezzie;
105
+ export { createBezzie, cloudflareKV };
106
+ export type { Variables } from './middleware';
107
+ export type { SessionAdapter, PKCEState, Session } from './session';
108
+ export { CloudflareKVAdapter, RedisAdapter, MemoryAdapter } from './session';
109
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAEnD,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,cAAc,CAAA;AAEzD,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,WAAW,CAAA;AAEpE;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IAEd;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IAEpB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;OAEG;IACH,OAAO,EAAE,cAAc,CAAA;IAEvB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IAEf;;OAEG;IACH,aAAa,CAAC,EAAE;QACd;;WAEG;QACH,SAAS,CAAC,EAAE,MAAM,CAAA;QAElB;;WAEG;QACH,aAAa,CAAC,EAAE,MAAM,CAAA;KACvB,CAAA;CACF;AAED;;GAEG;AACH,eAAO,MAAM,SAAS;IACpB;;OAEG;oBACa,MAAM;;;;;;IAOtB;;OAEG;mBACY,MAAM;;;IAIrB;;OAEG;wBACiB,MAAM,SAAS,MAAM;;;IAIzC;;OAEG;;;;CAIJ,CAAA;AAED;;GAEG;AACH,iBAAS,YAAY,CAAC,EAAE,EAAE,WAAW,GAAG,cAAc,CAErD;AAED;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB;;OAEG;IACH,MAAM,EAAE,MAAM,IAAI,CAAA;IAElB;;OAEG;IACH,UAAU,EAAE,MAAM,iBAAiB,CAAC;QAAE,SAAS,EAAE,SAAS,CAAA;KAAE,CAAC,CAAA;CAC9D;AAED;;;;;;GAMG;AACH,iBAAS,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAwBlD;AAED,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,CAAA;AACrC,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAC7C,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnE,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,73 @@
1
+ import { authRoutes } from './routes';
2
+ import { middleware } from './middleware';
3
+ import { CloudflareKVAdapter } from './session';
4
+ /**
5
+ * Common OIDC provider configurations.
6
+ */
7
+ export const providers = {
8
+ /**
9
+ * Auth0 provider configuration.
10
+ */
11
+ auth0: (domain) => ({
12
+ issuer: `https://${domain}`,
13
+ providerHints: {
14
+ logoutUrl: `https://${domain}/v2/logout`,
15
+ },
16
+ }),
17
+ /**
18
+ * Okta provider configuration.
19
+ */
20
+ okta: (domain) => ({
21
+ issuer: `https://${domain}/oauth2/default`,
22
+ }),
23
+ /**
24
+ * Keycloak provider configuration.
25
+ */
26
+ keycloak: (baseUrl, realm) => ({
27
+ issuer: `${baseUrl}/realms/${realm}`,
28
+ }),
29
+ /**
30
+ * Google provider configuration.
31
+ */
32
+ google: () => ({
33
+ issuer: 'https://accounts.google.com',
34
+ }),
35
+ };
36
+ /**
37
+ * Creates a Cloudflare KV session adapter.
38
+ */
39
+ function cloudflareKV(kv) {
40
+ return new CloudflareKVAdapter(kv);
41
+ }
42
+ /**
43
+ * Creates a new Bezzie instance.
44
+ *
45
+ * @param config Bezzie configuration
46
+ * @returns Bezzie instance
47
+ * @throws {Error} if required configuration is missing or invalid
48
+ */
49
+ function createBezzie(config) {
50
+ const required = ['issuer', 'clientId', 'clientSecret', 'adapter', 'baseUrl'];
51
+ for (const key of required) {
52
+ if (!config[key]) {
53
+ throw new Error(`Bezzie: missing required config: ${key}`);
54
+ }
55
+ }
56
+ if (!config.issuer.startsWith('https://')) {
57
+ throw new Error('Bezzie: issuer must start with https://');
58
+ }
59
+ try {
60
+ new URL(config.issuer);
61
+ }
62
+ catch (e) {
63
+ throw new Error('Bezzie: issuer must be a valid URL');
64
+ }
65
+ const router = authRoutes(config);
66
+ return {
67
+ routes: () => router,
68
+ middleware: () => middleware(config),
69
+ };
70
+ }
71
+ export { createBezzie, cloudflareKV };
72
+ export { CloudflareKVAdapter, RedisAdapter, MemoryAdapter } from './session';
73
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,EAAE,UAAU,EAAkB,MAAM,cAAc,CAAA;AAEzD,OAAO,EAAE,mBAAmB,EAAuB,MAAM,WAAW,CAAA;AAoDpE;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB;;OAEG;IACH,KAAK,EAAE,CAAC,MAAc,EAAE,EAAE,CAAC,CAAC;QAC1B,MAAM,EAAE,WAAW,MAAM,EAAE;QAC3B,aAAa,EAAE;YACb,SAAS,EAAE,WAAW,MAAM,YAAY;SACzC;KACF,CAAC;IAEF;;OAEG;IACH,IAAI,EAAE,CAAC,MAAc,EAAE,EAAE,CAAC,CAAC;QACzB,MAAM,EAAE,WAAW,MAAM,iBAAiB;KAC3C,CAAC;IAEF;;OAEG;IACH,QAAQ,EAAE,CAAC,OAAe,EAAE,KAAa,EAAE,EAAE,CAAC,CAAC;QAC7C,MAAM,EAAE,GAAG,OAAO,WAAW,KAAK,EAAE;KACrC,CAAC;IAEF;;OAEG;IACH,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACb,MAAM,EAAE,6BAA6B;KACtC,CAAC;CACH,CAAA;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,EAAe;IACnC,OAAO,IAAI,mBAAmB,CAAC,EAAE,CAAC,CAAA;AACpC,CAAC;AAiBD;;;;;;GAMG;AACH,SAAS,YAAY,CAAC,MAAoB;IACxC,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,CAAC,CAAA;IAC7E,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,CAAC,MAAM,CAAC,GAAyB,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CAAC,oCAAoC,GAAG,EAAE,CAAC,CAAA;QAC5D,CAAC;IACH,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAA;IAC5D,CAAC;IAED,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACxB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;IACvD,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;IAEjC,OAAO;QACL,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM;QACpB,UAAU,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;KACrC,CAAA;AACH,CAAC;AAED,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,CAAA;AAGrC,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA"}
@@ -0,0 +1,22 @@
1
+ import type { MiddlewareHandler } from 'hono';
2
+ import type { Session } from './session';
3
+ import type { BezzieConfig } from './index';
4
+ /**
5
+ * Hono context variables provided by Bezzie middleware.
6
+ * These are what downstream route handlers read from `c.var`.
7
+ */
8
+ export type Variables = {
9
+ /**
10
+ * The authenticated user's information.
11
+ */
12
+ user: Session['user'];
13
+ /**
14
+ * The current OAuth access token.
15
+ */
16
+ accessToken: string;
17
+ };
18
+ export declare function _resetDiscoveryCache(): void;
19
+ export declare function middleware(config: BezzieConfig): MiddlewareHandler<{
20
+ Variables: Variables;
21
+ }>;
22
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAG7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE3C;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;IACrB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAkBD,wBAAgB,oBAAoB,SAGnC;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,iBAAiB,CAAC;IAAE,SAAS,EAAE,SAAS,CAAA;CAAE,CAAC,CAuE5F"}
@@ -0,0 +1,81 @@
1
+ import { getCookie } from 'hono/cookie';
2
+ import * as oauth from 'oauth4webapi';
3
+ const jwksCache = {};
4
+ let cachedAS = null;
5
+ let cacheExpiresAt = 0;
6
+ async function getAuthorizationServer(config) {
7
+ if (cachedAS && Date.now() < cacheExpiresAt)
8
+ return cachedAS;
9
+ const issuerUrl = new URL(config.issuer);
10
+ const response = await oauth.discoveryRequest(issuerUrl);
11
+ const as = await oauth.processDiscoveryResponse(issuerUrl, response);
12
+ cachedAS = config.providerHints?.tokenEndpoint
13
+ ? { ...as, token_endpoint: config.providerHints.tokenEndpoint }
14
+ : as;
15
+ cacheExpiresAt = Date.now() + 60 * 60 * 1000; // 1 hour
16
+ return cachedAS;
17
+ }
18
+ export function _resetDiscoveryCache() {
19
+ cachedAS = null;
20
+ cacheExpiresAt = 0;
21
+ }
22
+ export function middleware(config) {
23
+ const sessionStore = config.adapter;
24
+ return async (c, next) => {
25
+ // 1. Read the sessionId cookie from the request
26
+ const sessionId = getCookie(c, 'sessionId');
27
+ // 2. If no cookie → return 401
28
+ if (!sessionId) {
29
+ return c.text('Unauthorized', 401);
30
+ }
31
+ // 3. Look up the session in KV using SessionStore
32
+ const session = await sessionStore.get(sessionId);
33
+ // 4. If no session found or it's a PKCE state → return 401
34
+ if (!session || 'codeVerifier' in session) {
35
+ return c.text('Unauthorized', 401);
36
+ }
37
+ const as = await getAuthorizationServer(config);
38
+ // 5. Check if the access token is expired (with 60s buffer)
39
+ if (session.expiresAt < (Date.now() / 1000) + 60) {
40
+ // 6. If expired → use oauth4webapi to perform a refresh token grant
41
+ const client = {
42
+ client_id: config.clientId,
43
+ client_secret: config.clientSecret,
44
+ token_endpoint_auth_method: 'client_secret_post',
45
+ };
46
+ const response = await oauth.refreshTokenGrantRequest(as, client, session.refreshToken);
47
+ const result = await oauth.processRefreshTokenResponse(as, client, response);
48
+ if (oauth.isOAuth2Error(result)) {
49
+ await sessionStore.delete(sessionId);
50
+ return c.text('Unauthorized', 401);
51
+ }
52
+ // Update the session in KV with new tokens and new expiresAt
53
+ session.accessToken = result.access_token;
54
+ if (result.refresh_token) {
55
+ session.refreshToken = result.refresh_token;
56
+ }
57
+ session.expiresAt = Math.floor(Date.now() / 1000) + (result.expires_in || 3600);
58
+ await sessionStore.set(sessionId, session, 30 * 24 * 60 * 60); // 30 days, matches initial session TTL
59
+ }
60
+ // 8. Validate the JWT using JWKS
61
+ try {
62
+ // We need a Request object that has the Authorization header for validateJwtAccessToken
63
+ const mockReq = new Request(c.req.raw.url, {
64
+ headers: {
65
+ Authorization: `Bearer ${session.accessToken}`,
66
+ },
67
+ });
68
+ await oauth.validateJwtAccessToken(as, mockReq, config.audience ?? '', { [oauth.jwksCache]: jwksCache });
69
+ }
70
+ catch (error) {
71
+ // 9. If JWT invalid → return 401
72
+ return c.text('Unauthorized', 401);
73
+ }
74
+ // 10. Attach the user and accessToken to Hono context
75
+ c.set('user', session.user);
76
+ c.set('accessToken', session.accessToken);
77
+ // 12. Call next()
78
+ await next();
79
+ };
80
+ }
81
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { Hono } from 'hono';
2
+ import type { BezzieConfig } from './index';
3
+ export declare function _resetDiscoveryCache(): void;
4
+ export declare function authRoutes(config: BezzieConfig): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
5
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAI3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAiB3C,wBAAgB,oBAAoB,SAGnC;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,8EA0I9C"}
package/dist/routes.js ADDED
@@ -0,0 +1,131 @@
1
+ import { Hono } from 'hono';
2
+ import { getCookie, setCookie, deleteCookie } from 'hono/cookie';
3
+ import * as oauth from 'oauth4webapi';
4
+ let cachedAS = null;
5
+ let cacheExpiresAt = 0;
6
+ async function getAuthorizationServer(config) {
7
+ if (cachedAS && Date.now() < cacheExpiresAt)
8
+ return cachedAS;
9
+ const issuerUrl = new URL(config.issuer);
10
+ const response = await oauth.discoveryRequest(issuerUrl);
11
+ const as = await oauth.processDiscoveryResponse(issuerUrl, response);
12
+ cachedAS = config.providerHints?.tokenEndpoint
13
+ ? { ...as, token_endpoint: config.providerHints.tokenEndpoint }
14
+ : as;
15
+ cacheExpiresAt = Date.now() + 60 * 60 * 1000; // 1 hour
16
+ return cachedAS;
17
+ }
18
+ export function _resetDiscoveryCache() {
19
+ cachedAS = null;
20
+ cacheExpiresAt = 0;
21
+ }
22
+ export function authRoutes(config) {
23
+ const router = new Hono();
24
+ const sessionStore = config.adapter;
25
+ router.get('/login', async (c) => {
26
+ const code_verifier = oauth.generateRandomCodeVerifier();
27
+ const code_challenge = await oauth.calculatePKCECodeChallenge(code_verifier);
28
+ const state = oauth.generateRandomState();
29
+ const returnTo = c.req.query('returnTo');
30
+ // Store state and codeVerifier in adapter
31
+ await config.adapter.set(`pkce:${state}`, { codeVerifier: code_verifier, returnTo }, 600); // 10 minutes
32
+ const as = await getAuthorizationServer(config);
33
+ if (!as.authorization_endpoint) {
34
+ return c.text('Missing authorization_endpoint', 500);
35
+ }
36
+ const authorizationUrl = new URL(as.authorization_endpoint);
37
+ authorizationUrl.searchParams.set('client_id', config.clientId);
38
+ authorizationUrl.searchParams.set('response_type', 'code');
39
+ authorizationUrl.searchParams.set('redirect_uri', `${config.baseUrl}/auth/callback`);
40
+ authorizationUrl.searchParams.set('scope', 'openid profile email offline_access');
41
+ authorizationUrl.searchParams.set('state', state);
42
+ authorizationUrl.searchParams.set('code_challenge', code_challenge);
43
+ authorizationUrl.searchParams.set('code_challenge_method', 'S256');
44
+ if (config.audience) {
45
+ authorizationUrl.searchParams.set('audience', config.audience);
46
+ }
47
+ return c.redirect(authorizationUrl.toString());
48
+ });
49
+ router.get('/callback', async (c) => {
50
+ const error = c.req.query('error');
51
+ if (error) {
52
+ return c.text(`OAuth error: ${error}`, 400);
53
+ }
54
+ const state = c.req.query('state');
55
+ const code = c.req.query('code');
56
+ if (!state || !code) {
57
+ return c.text('Missing state or code', 400);
58
+ }
59
+ const stored = await config.adapter.get(`pkce:${state}`);
60
+ if (!stored) {
61
+ return c.text('Invalid or expired state', 400);
62
+ }
63
+ const { codeVerifier, returnTo } = stored;
64
+ await config.adapter.delete(`pkce:${state}`);
65
+ const as = await getAuthorizationServer(config);
66
+ const client = {
67
+ client_id: config.clientId,
68
+ client_secret: config.clientSecret,
69
+ token_endpoint_auth_method: 'client_secret_post',
70
+ };
71
+ const response = await oauth.authorizationCodeGrantRequest(as, client, new URL(c.req.url).searchParams, `${config.baseUrl}/auth/callback`, codeVerifier);
72
+ const result = await oauth.processAuthorizationCodeOpenIDResponse(as, client, response);
73
+ if (oauth.isOAuth2Error(result)) {
74
+ return c.text('OAuth 2.0 error', 400);
75
+ }
76
+ const { access_token, refresh_token, expires_in } = result;
77
+ const claims = oauth.getValidatedIdTokenClaims(result);
78
+ const sessionId = crypto.randomUUID();
79
+ const session = {
80
+ accessToken: access_token,
81
+ refreshToken: refresh_token || '',
82
+ expiresAt: Math.floor(Date.now() / 1000) + (expires_in || 3600),
83
+ user: {
84
+ ...claims,
85
+ sub: claims.sub,
86
+ email: claims.email,
87
+ },
88
+ };
89
+ // TTL for session in KV. Set to 30 days as per bug fix 3.
90
+ await sessionStore.set(sessionId, session, 30 * 24 * 60 * 60);
91
+ setCookie(c, 'sessionId', sessionId, {
92
+ httpOnly: true,
93
+ secure: true,
94
+ sameSite: 'Strict',
95
+ path: '/',
96
+ });
97
+ if (returnTo && returnTo.startsWith('/') && !returnTo.startsWith('//')) {
98
+ return c.redirect(returnTo);
99
+ }
100
+ return c.redirect('/');
101
+ });
102
+ router.get('/logout', async (c) => {
103
+ const sessionId = getCookie(c, 'sessionId');
104
+ if (sessionId) {
105
+ await sessionStore.delete(sessionId);
106
+ }
107
+ deleteCookie(c, 'sessionId', {
108
+ path: '/',
109
+ secure: true,
110
+ });
111
+ const as = await getAuthorizationServer(config);
112
+ let logoutUrl;
113
+ if (config.providerHints?.logoutUrl) {
114
+ logoutUrl = new URL(config.providerHints.logoutUrl);
115
+ logoutUrl.searchParams.set('client_id', config.clientId);
116
+ logoutUrl.searchParams.set('returnTo', config.baseUrl);
117
+ }
118
+ else if (as.end_session_endpoint) {
119
+ logoutUrl = new URL(as.end_session_endpoint);
120
+ logoutUrl.searchParams.set('client_id', config.clientId);
121
+ logoutUrl.searchParams.set('post_logout_redirect_uri', config.baseUrl);
122
+ }
123
+ else {
124
+ // If no endpoint found, we just redirect to base URL
125
+ return c.redirect('/');
126
+ }
127
+ return c.redirect(logoutUrl.toString());
128
+ });
129
+ return router;
130
+ }
131
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Represents a user session.
3
+ */
4
+ export interface Session {
5
+ /**
6
+ * OAuth access token.
7
+ */
8
+ accessToken: string;
9
+ /**
10
+ * OAuth refresh token.
11
+ */
12
+ refreshToken: string;
13
+ /**
14
+ * Expiration time of the access token as a Unix timestamp (seconds).
15
+ */
16
+ expiresAt: number;
17
+ /**
18
+ * User information from the ID token or userinfo endpoint.
19
+ */
20
+ user: {
21
+ /**
22
+ * Unique identifier for the user.
23
+ */
24
+ sub: string;
25
+ /**
26
+ * User's email address.
27
+ */
28
+ email?: string;
29
+ [key: string]: unknown;
30
+ };
31
+ }
32
+ export * from './adapters';
33
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB;;OAEG;IACH,IAAI,EAAE;QACJ;;WAEG;QACH,GAAG,EAAE,MAAM,CAAA;QACX;;WAEG;QACH,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KACvB,CAAA;CACF;AAED,cAAc,YAAY,CAAA"}
@@ -0,0 +1,2 @@
1
+ export * from './adapters';
2
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAgCA,cAAc,YAAY,CAAA"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "bezzie",
3
+ "version": "0.1.0",
4
+ "description": "BFF OAuth 2.0 auth library for Cloudflare Workers",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "types": "./dist/index.d.ts"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "license": "MIT",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/neilpmas/bezzie"
20
+ },
21
+ "scripts": {
22
+ "dev": "wrangler dev",
23
+ "build": "tsc",
24
+ "test": "vitest run",
25
+ "lint": "eslint src test --ext .ts",
26
+ "format": "prettier --write src test",
27
+ "prepublishOnly": "npm run build && npm test && npm run lint"
28
+ },
29
+ "dependencies": {
30
+ "oauth4webapi": "^2.0.0"
31
+ },
32
+ "peerDependencies": {
33
+ "hono": "^4.0.0"
34
+ },
35
+ "devDependencies": {
36
+ "@cloudflare/vitest-pool-workers": "^0.5.0",
37
+ "@cloudflare/workers-types": "^4.0.0",
38
+ "@typescript-eslint/eslint-plugin": "^7.0.0",
39
+ "@typescript-eslint/parser": "^7.0.0",
40
+ "eslint": "^8.0.0",
41
+ "prettier": "^3.0.0",
42
+ "typescript": "^5.0.0",
43
+ "vitest": "^2.1.0",
44
+ "wrangler": "^3.0.0"
45
+ }
46
+ }