oauth.do 0.2.0 → 0.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/dist/hono.js CHANGED
@@ -1,5 +1,406 @@
1
- import { getCookie } from 'hono/cookie';
1
+ import { getCookie, deleteCookie, setCookie } from 'hono/cookie';
2
2
  import * as jose from 'jose';
3
+ import { Hono } from 'hono';
4
+
5
+ // src/hono.ts
6
+
7
+ // src/session.ts
8
+ var defaultSessionConfig = {
9
+ cookieName: "session",
10
+ cookieMaxAge: 60 * 60 * 24 * 7,
11
+ // 7 days
12
+ cookieSecure: true,
13
+ cookieSameSite: "lax",
14
+ secret: "oauth-do-dev-secret-change-in-production"
15
+ };
16
+ var ALGORITHM = "AES-GCM";
17
+ var IV_LENGTH = 12;
18
+ var TAG_LENGTH = 128;
19
+ async function getEncryptionKey(secret) {
20
+ const encoder = new TextEncoder();
21
+ return crypto.subtle.importKey(
22
+ "raw",
23
+ encoder.encode(secret.padEnd(32, "0").slice(0, 32)),
24
+ { name: ALGORITHM },
25
+ false,
26
+ ["encrypt", "decrypt"]
27
+ );
28
+ }
29
+ async function encodeSession(session, secret) {
30
+ const key = await getEncryptionKey(secret ?? defaultSessionConfig.secret);
31
+ const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));
32
+ const encoder = new TextEncoder();
33
+ const data = encoder.encode(JSON.stringify(session));
34
+ const ciphertext = await crypto.subtle.encrypt(
35
+ { name: ALGORITHM, iv, tagLength: TAG_LENGTH },
36
+ key,
37
+ data
38
+ );
39
+ const combined2 = new Uint8Array(iv.length + ciphertext.byteLength);
40
+ combined2.set(iv, 0);
41
+ combined2.set(new Uint8Array(ciphertext), iv.length);
42
+ return btoa(String.fromCharCode(...combined2));
43
+ }
44
+ async function decodeSession(encoded, secret) {
45
+ try {
46
+ const key = await getEncryptionKey(secret ?? defaultSessionConfig.secret);
47
+ const combined2 = Uint8Array.from(atob(encoded), (c) => c.charCodeAt(0));
48
+ const iv = combined2.slice(0, IV_LENGTH);
49
+ const ciphertext = combined2.slice(IV_LENGTH);
50
+ const decrypted = await crypto.subtle.decrypt(
51
+ { name: ALGORITHM, iv, tagLength: TAG_LENGTH },
52
+ key,
53
+ ciphertext
54
+ );
55
+ const decoder = new TextDecoder();
56
+ const parsed = JSON.parse(decoder.decode(decrypted));
57
+ if (!isValidSessionData(parsed)) {
58
+ return null;
59
+ }
60
+ return parsed;
61
+ } catch {
62
+ return null;
63
+ }
64
+ }
65
+ function isValidSessionData(data) {
66
+ if (data === null || typeof data !== "object") {
67
+ return false;
68
+ }
69
+ const session = data;
70
+ if (typeof session.userId !== "string" || session.userId.length === 0) {
71
+ return false;
72
+ }
73
+ if (typeof session.accessToken !== "string" || session.accessToken.length === 0) {
74
+ return false;
75
+ }
76
+ if (session.organizationId !== void 0 && typeof session.organizationId !== "string") {
77
+ return false;
78
+ }
79
+ if (session.email !== void 0 && typeof session.email !== "string") {
80
+ return false;
81
+ }
82
+ if (session.name !== void 0 && typeof session.name !== "string") {
83
+ return false;
84
+ }
85
+ if (session.refreshToken !== void 0 && typeof session.refreshToken !== "string") {
86
+ return false;
87
+ }
88
+ if (session.expiresAt !== void 0 && typeof session.expiresAt !== "number") {
89
+ return false;
90
+ }
91
+ return true;
92
+ }
93
+ function getSessionConfig(env) {
94
+ const validSameSite = ["strict", "lax", "none"];
95
+ let cookieSameSite = defaultSessionConfig.cookieSameSite;
96
+ if (env?.SESSION_COOKIE_SAME_SITE) {
97
+ const value = env.SESSION_COOKIE_SAME_SITE;
98
+ if (validSameSite.includes(value)) {
99
+ cookieSameSite = value;
100
+ }
101
+ }
102
+ let cookieMaxAge = defaultSessionConfig.cookieMaxAge;
103
+ if (env?.SESSION_COOKIE_MAX_AGE) {
104
+ const parsed = parseInt(env.SESSION_COOKIE_MAX_AGE, 10);
105
+ if (!Number.isNaN(parsed) && parsed > 0) {
106
+ cookieMaxAge = parsed;
107
+ }
108
+ }
109
+ return {
110
+ secret: env?.SESSION_SECRET ?? defaultSessionConfig.secret,
111
+ cookieName: env?.SESSION_COOKIE_NAME ?? defaultSessionConfig.cookieName,
112
+ cookieMaxAge,
113
+ cookieSecure: env?.SESSION_COOKIE_SECURE !== "false",
114
+ cookieSameSite
115
+ };
116
+ }
117
+
118
+ // src/session-hono.ts
119
+ async function setSessionCookie(c, session, config = defaultSessionConfig) {
120
+ const encoded = await encodeSession(session, config.secret);
121
+ setCookie(c, config.cookieName, encoded, {
122
+ path: "/",
123
+ httpOnly: true,
124
+ secure: config.cookieSecure,
125
+ sameSite: config.cookieSameSite === "none" ? "None" : config.cookieSameSite === "strict" ? "Strict" : "Lax",
126
+ maxAge: config.cookieMaxAge
127
+ });
128
+ }
129
+ function clearSessionCookie(c, config = defaultSessionConfig) {
130
+ deleteCookie(c, config.cookieName, { path: "/" });
131
+ }
132
+ async function getSessionFromCookie(c, config = defaultSessionConfig) {
133
+ const encoded = getCookie(c, config.cookieName);
134
+ if (!encoded) return null;
135
+ return decodeSession(encoded, config.secret);
136
+ }
137
+ function sessionAuth(options = {}) {
138
+ return async (c, next) => {
139
+ const env = c.env ?? {};
140
+ const config = { ...getSessionConfig(env), ...options.config };
141
+ const session = await getSessionFromCookie(c, config);
142
+ c.set("session", session);
143
+ c.set("sessionUser", session ? {
144
+ id: session.userId,
145
+ email: session.email,
146
+ name: session.name,
147
+ organizationId: session.organizationId
148
+ } : null);
149
+ await next();
150
+ };
151
+ }
152
+ function requireSession(options = {}) {
153
+ return async (c, next) => {
154
+ const env = c.env ?? {};
155
+ const config = { ...getSessionConfig(env), ...options.config };
156
+ const session = await getSessionFromCookie(c, config);
157
+ if (!session) {
158
+ return c.json({ error: "Unauthorized", message: "Authentication required" }, 401);
159
+ }
160
+ if (session.expiresAt && Date.now() >= session.expiresAt) {
161
+ clearSessionCookie(c, config);
162
+ return c.json({ error: "Unauthorized", message: "Session expired" }, 401);
163
+ }
164
+ c.set("session", session);
165
+ c.set("sessionUser", {
166
+ id: session.userId,
167
+ email: session.email,
168
+ name: session.name,
169
+ organizationId: session.organizationId
170
+ });
171
+ await next();
172
+ };
173
+ }
174
+ function createWorkOSClient(apiKey2) {
175
+ const baseUrl = "https://api.workos.com";
176
+ return {
177
+ getAuthorizationUrl(options) {
178
+ const params = new URLSearchParams({
179
+ client_id: options.clientId,
180
+ redirect_uri: options.redirectUri,
181
+ response_type: "code",
182
+ ...options.state && { state: options.state },
183
+ ...options.provider && { provider: options.provider }
184
+ });
185
+ return `https://api.workos.com/sso/authorize?${params.toString()}`;
186
+ },
187
+ async authenticateWithCode(options) {
188
+ const response = await fetch(`${baseUrl}/user_management/authenticate`, {
189
+ method: "POST",
190
+ headers: {
191
+ "Content-Type": "application/x-www-form-urlencoded",
192
+ "Authorization": `Bearer ${apiKey2}`
193
+ },
194
+ body: new URLSearchParams({
195
+ grant_type: "authorization_code",
196
+ client_id: options.clientId,
197
+ code: options.code,
198
+ redirect_uri: options.redirectUri
199
+ }).toString()
200
+ });
201
+ if (!response.ok) {
202
+ const error = await response.text();
203
+ throw new Error(`WorkOS authentication failed: ${response.status} - ${error}`);
204
+ }
205
+ return response.json();
206
+ },
207
+ async refreshToken(options) {
208
+ const response = await fetch(`${baseUrl}/user_management/authenticate`, {
209
+ method: "POST",
210
+ headers: {
211
+ "Content-Type": "application/x-www-form-urlencoded",
212
+ "Authorization": `Bearer ${apiKey2}`
213
+ },
214
+ body: new URLSearchParams({
215
+ grant_type: "refresh_token",
216
+ client_id: options.clientId,
217
+ refresh_token: options.refreshToken
218
+ }).toString()
219
+ });
220
+ if (!response.ok) {
221
+ const error = await response.text();
222
+ throw new Error(`Token refresh failed: ${response.status} - ${error}`);
223
+ }
224
+ return response.json();
225
+ }
226
+ };
227
+ }
228
+ function createOAuthRoutes(options = {}) {
229
+ const app = new Hono();
230
+ app.use("*", async (c, next) => {
231
+ await next();
232
+ const contentType = c.res.headers.get("content-type");
233
+ if (contentType?.includes("application/json") && !contentType.includes("charset")) {
234
+ c.res.headers.set("content-type", "application/json; charset=utf-8");
235
+ }
236
+ });
237
+ app.get("/login", (c) => {
238
+ const env = c.env ?? {};
239
+ const apiKey2 = options.workosApiKey ?? env.WORKOS_API_KEY;
240
+ const clientId = options.clientId ?? env.WORKOS_CLIENT_ID;
241
+ if (!apiKey2) {
242
+ return c.json({ error: "Server configuration error", message: "WORKOS_API_KEY not configured" }, 500);
243
+ }
244
+ if (!clientId) {
245
+ return c.json({ error: "Server configuration error", message: "WORKOS_CLIENT_ID not configured" }, 500);
246
+ }
247
+ const workos = createWorkOSClient(apiKey2);
248
+ const url = new URL(c.req.url);
249
+ const baseUrl = options.redirectBaseUrl ?? env.AUTH_REDIRECT_BASE_URL ?? `${url.protocol}//${url.host}`;
250
+ const intendedRedirect = c.req.query("redirect_uri") || "/";
251
+ const provider = c.req.query("provider");
252
+ const state = btoa(JSON.stringify({ redirect: intendedRedirect }));
253
+ const authUrl = workos.getAuthorizationUrl({
254
+ clientId,
255
+ redirectUri: `${baseUrl}/auth/callback`,
256
+ state,
257
+ provider
258
+ });
259
+ return c.redirect(authUrl);
260
+ });
261
+ app.get("/callback", async (c) => {
262
+ const env = c.env ?? {};
263
+ const apiKey2 = options.workosApiKey ?? env.WORKOS_API_KEY;
264
+ const clientId = options.clientId ?? env.WORKOS_CLIENT_ID;
265
+ const sessionConfig = { ...getSessionConfig(env), ...options.session };
266
+ const debug = options.debug ?? env.DEBUG === "true";
267
+ if (!apiKey2) {
268
+ return c.json({ error: "Server configuration error", message: "WORKOS_API_KEY not configured" }, 500);
269
+ }
270
+ if (!clientId) {
271
+ return c.json({ error: "Server configuration error", message: "WORKOS_CLIENT_ID not configured" }, 500);
272
+ }
273
+ const code = c.req.query("code");
274
+ const state = c.req.query("state");
275
+ const error = c.req.query("error");
276
+ const errorDescription = c.req.query("error_description");
277
+ if (error) {
278
+ if (debug) console.error("[Auth] OAuth error:", error, errorDescription);
279
+ return c.json({ error: "Authentication failed", message: errorDescription || error }, 400);
280
+ }
281
+ if (!code) {
282
+ return c.json({ error: "Missing authorization code" }, 400);
283
+ }
284
+ const workos = createWorkOSClient(apiKey2);
285
+ const url = new URL(c.req.url);
286
+ const baseUrl = options.redirectBaseUrl ?? env.AUTH_REDIRECT_BASE_URL ?? `${url.protocol}//${url.host}`;
287
+ try {
288
+ const result = await workos.authenticateWithCode({
289
+ clientId,
290
+ code,
291
+ redirectUri: `${baseUrl}/auth/callback`
292
+ });
293
+ const session = {
294
+ userId: result.user.id,
295
+ organizationId: result.user.organization_id,
296
+ email: result.user.email,
297
+ name: [result.user.first_name, result.user.last_name].filter(Boolean).join(" ") || void 0,
298
+ accessToken: result.access_token,
299
+ refreshToken: result.refresh_token,
300
+ expiresAt: result.expires_in ? Date.now() + result.expires_in * 1e3 : void 0
301
+ };
302
+ await setSessionCookie(c, session, sessionConfig);
303
+ await options.onLogin?.(session, c);
304
+ let redirectTo = "/";
305
+ if (state) {
306
+ try {
307
+ const stateData = JSON.parse(atob(state));
308
+ redirectTo = stateData.redirect || "/";
309
+ } catch {
310
+ }
311
+ }
312
+ if (!redirectTo.startsWith("/")) {
313
+ redirectTo = "/";
314
+ }
315
+ return c.redirect(redirectTo);
316
+ } catch (err) {
317
+ if (debug) console.error("[Auth] OAuth callback error:", err);
318
+ return c.json({
319
+ error: "Authentication failed",
320
+ message: err instanceof Error ? err.message : "Unknown error"
321
+ }, 500);
322
+ }
323
+ });
324
+ app.get("/logout", async (c) => {
325
+ const env = c.env ?? {};
326
+ const sessionConfig = { ...getSessionConfig(env), ...options.session };
327
+ clearSessionCookie(c, sessionConfig);
328
+ await options.onLogout?.(c);
329
+ const redirectTo = c.req.query("redirect_uri") || "/";
330
+ if (!redirectTo.startsWith("/")) {
331
+ return c.redirect("/");
332
+ }
333
+ return c.redirect(redirectTo);
334
+ });
335
+ app.post("/logout", async (c) => {
336
+ const env = c.env ?? {};
337
+ const sessionConfig = { ...getSessionConfig(env), ...options.session };
338
+ clearSessionCookie(c, sessionConfig);
339
+ await options.onLogout?.(c);
340
+ return c.json({ success: true, message: "Logged out successfully" });
341
+ });
342
+ app.get("/me", async (c) => {
343
+ const env = c.env ?? {};
344
+ const sessionConfig = { ...getSessionConfig(env), ...options.session };
345
+ const session = await getSessionFromCookie(c, sessionConfig);
346
+ if (!session) {
347
+ return c.json({ error: "Unauthorized", message: "Not authenticated" }, 401);
348
+ }
349
+ if (session.expiresAt && Date.now() >= session.expiresAt) {
350
+ clearSessionCookie(c, sessionConfig);
351
+ return c.json({ error: "Unauthorized", message: "Session expired" }, 401);
352
+ }
353
+ return c.json({
354
+ id: session.userId,
355
+ email: session.email,
356
+ name: session.name,
357
+ organizationId: session.organizationId
358
+ });
359
+ });
360
+ app.post("/refresh", async (c) => {
361
+ const env = c.env ?? {};
362
+ const apiKey2 = options.workosApiKey ?? env.WORKOS_API_KEY;
363
+ const clientId = options.clientId ?? env.WORKOS_CLIENT_ID;
364
+ const sessionConfig = { ...getSessionConfig(env), ...options.session };
365
+ const debug = options.debug ?? env.DEBUG === "true";
366
+ if (!apiKey2) {
367
+ return c.json({ error: "Server configuration error", message: "WORKOS_API_KEY not configured" }, 500);
368
+ }
369
+ if (!clientId) {
370
+ return c.json({ error: "Server configuration error", message: "WORKOS_CLIENT_ID not configured" }, 500);
371
+ }
372
+ const session = await getSessionFromCookie(c, sessionConfig);
373
+ if (!session) {
374
+ return c.json({ error: "Unauthorized", message: "Not authenticated" }, 401);
375
+ }
376
+ if (!session.refreshToken) {
377
+ return c.json({ error: "Cannot refresh", message: "No refresh token available" }, 400);
378
+ }
379
+ const workos = createWorkOSClient(apiKey2);
380
+ try {
381
+ const result = await workos.refreshToken({
382
+ clientId,
383
+ refreshToken: session.refreshToken
384
+ });
385
+ const updatedSession = {
386
+ ...session,
387
+ accessToken: result.access_token,
388
+ refreshToken: result.refresh_token || session.refreshToken,
389
+ expiresAt: result.expires_in ? Date.now() + result.expires_in * 1e3 : void 0
390
+ };
391
+ await setSessionCookie(c, updatedSession, sessionConfig);
392
+ return c.json({ success: true, expiresAt: updatedSession.expiresAt });
393
+ } catch (err) {
394
+ if (debug) console.error("[Auth] Token refresh error:", err);
395
+ clearSessionCookie(c, sessionConfig);
396
+ return c.json({
397
+ error: "Refresh failed",
398
+ message: err instanceof Error ? err.message : "Unknown error"
399
+ }, 401);
400
+ }
401
+ });
402
+ return app;
403
+ }
3
404
 
4
405
  // src/hono.ts
5
406
  var OAUTH_DO_CONFIG = {
@@ -193,6 +594,6 @@ function combined(options) {
193
594
  };
194
595
  }
195
596
 
196
- export { apiKey, auth, combined, requireAuth };
597
+ export { apiKey, auth, combined, createOAuthRoutes, decodeSession, encodeSession, getSessionConfig, requireAuth, requireSession, sessionAuth };
197
598
  //# sourceMappingURL=hono.js.map
198
599
  //# sourceMappingURL=hono.js.map
package/dist/hono.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hono.ts"],"names":[],"mappings":"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","file":"hono.js","sourcesContent":["/**\n * oauth.do/hono - Hono middleware for authentication\n *\n * Lightweight authentication middleware for Cloudflare Workers.\n * Uses jose for JWT verification - no heavy WorkOS SDK dependency.\n *\n * @packageDocumentation\n */\n\nimport type { Context, MiddlewareHandler } from 'hono'\nimport { getCookie } from 'hono/cookie'\nimport type { JWTPayload } from 'jose'\nimport * as jose from 'jose'\n\n// Cloudflare Workers Cache API type\ndeclare const caches: {\n default: Cache\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Types\n// ═══════════════════════════════════════════════════════════════════════════\n\nexport interface AuthUser {\n id: string\n email?: string\n name?: string\n organizationId?: string\n roles?: string[]\n permissions?: string[]\n metadata?: Record<string, unknown>\n}\n\nexport interface AuthVariables {\n user: AuthUser | null\n userId: string | null\n isAuth: boolean\n token: string | null\n}\n\ndeclare module 'hono' {\n interface ContextVariableMap extends AuthVariables {}\n}\n\nexport interface AuthOptions {\n /** Cookie name for JWT token (default: 'auth') */\n cookieName?: string\n /** Header name for Bearer token (default: 'Authorization') */\n headerName?: string\n /** WorkOS Client ID (default: oauth.do client ID) */\n clientId?: string\n /** JWKS URI for token verification (default: WorkOS JWKS) */\n jwksUri?: string\n /** Skip auth for certain paths */\n skip?: (c: Context) => boolean\n /** Cache duration for JWKS in seconds (default: 3600) */\n jwksCacheTtl?: number\n}\n\nexport interface RequireAuthOptions extends AuthOptions {\n /** Redirect to login page instead of 401 */\n redirectTo?: string\n /** Required roles (any of) */\n roles?: string[]\n /** Required permissions (all of) */\n permissions?: string[]\n}\n\nexport interface ApiKeyOptions {\n /** Header name (default: 'X-API-Key') */\n headerName?: string\n /** Verify function - return user if valid, null if not */\n verify: (key: string, c: Context) => Promise<AuthUser | null>\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Constants\n// ═══════════════════════════════════════════════════════════════════════════\n\nconst OAUTH_DO_CONFIG = {\n clientId: 'client_01JQYTRXK9ZPD8JPJTKDCRB656',\n jwksUri: 'https://api.workos.com/sso/jwks/client_01JQYTRXK9ZPD8JPJTKDCRB656',\n}\n\nconst TOKEN_CACHE_TTL = 5 * 60 // 5 minutes\nconst CACHE_URL_PREFIX = 'https://oauth.do/_cache/token/'\n\n// ═══════════════════════════════════════════════════════════════════════════\n// JWT Utilities\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Hash a token for cache key (avoids storing raw tokens in cache)\n */\nasync function hashToken(token: string): Promise<string> {\n const data = new TextEncoder().encode(token)\n const hashBuffer = await crypto.subtle.digest('SHA-256', data)\n return Array.from(new Uint8Array(hashBuffer))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Get cached user from Cache API\n */\nasync function getCachedUser(token: string): Promise<AuthUser | null> {\n try {\n const cache = caches.default\n const hash = await hashToken(token)\n const cacheKey = new Request(`${CACHE_URL_PREFIX}${hash}`)\n const cached = await cache.match(cacheKey)\n\n if (!cached) return null\n\n const data = await cached.json() as { user: AuthUser; expiresAt: number }\n if (data.expiresAt < Date.now()) return null\n\n return data.user\n } catch {\n return null\n }\n}\n\n/**\n * Cache user in Cache API\n */\nasync function cacheUser(token: string, user: AuthUser): Promise<void> {\n try {\n const cache = caches.default\n const hash = await hashToken(token)\n const cacheKey = new Request(`${CACHE_URL_PREFIX}${hash}`)\n const data = { user, expiresAt: Date.now() + TOKEN_CACHE_TTL * 1000 }\n const response = new Response(JSON.stringify(data), {\n headers: { 'Cache-Control': `max-age=${TOKEN_CACHE_TTL}` },\n })\n await cache.put(cacheKey, response)\n } catch {\n // Cache failures are non-fatal\n }\n}\n\n/**\n * Extract JWT from request (cookie or Bearer header)\n */\nfunction extractToken(c: Context, cookieName: string, headerName: string): string | null {\n // Try Bearer header first\n const authHeader = c.req.header(headerName)\n if (authHeader?.startsWith('Bearer ')) {\n return authHeader.slice(7)\n }\n\n // Try cookie\n const cookie = getCookie(c, cookieName)\n if (cookie) return cookie\n\n return null\n}\n\n/**\n * Convert JWT payload to AuthUser\n */\nfunction payloadToUser(payload: JWTPayload): AuthUser {\n return {\n id: payload.sub || '',\n email: payload.email as string | undefined,\n name: payload.name as string | undefined,\n organizationId: payload.org_id as string | undefined,\n roles: payload.roles as string[] | undefined,\n permissions: payload.permissions as string[] | undefined,\n metadata: payload.metadata as Record<string, unknown> | undefined,\n }\n}\n\n// JWKS cache (module-level, persists across requests)\nlet jwksCache: jose.JWTVerifyGetKey | null = null\nlet jwksCacheExpiry = 0\n\n/**\n * Get JWKS verifier with caching\n */\nasync function getJwks(jwksUri: string, cacheTtl: number): Promise<jose.JWTVerifyGetKey> {\n const now = Date.now()\n if (jwksCache && jwksCacheExpiry > now) {\n return jwksCache\n }\n\n jwksCache = jose.createRemoteJWKSet(new URL(jwksUri))\n jwksCacheExpiry = now + cacheTtl * 1000\n return jwksCache\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Middleware\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Auth middleware - populates c.var.user if authenticated\n *\n * Does NOT reject unauthenticated requests. Use requireAuth() for that.\n *\n * @example\n * ```ts\n * import { Hono } from 'hono'\n * import { auth } from 'oauth.do/hono'\n *\n * const app = new Hono()\n * app.use('*', auth())\n *\n * app.get('/api/me', (c) => {\n * if (!c.var.user) return c.json({ error: 'Not authenticated' }, 401)\n * return c.json(c.var.user)\n * })\n * ```\n */\nexport function auth(options: AuthOptions = {}): MiddlewareHandler {\n const {\n cookieName = 'auth',\n headerName = 'Authorization',\n clientId = OAUTH_DO_CONFIG.clientId,\n jwksUri = OAUTH_DO_CONFIG.jwksUri,\n skip,\n jwksCacheTtl = 3600,\n } = options\n\n return async (c, next) => {\n // Initialize variables\n c.set('user', null)\n c.set('userId', null)\n c.set('isAuth', false)\n c.set('token', null)\n\n // Skip if configured\n if (skip?.(c)) {\n return next()\n }\n\n const token = extractToken(c, cookieName, headerName)\n if (!token) {\n return next()\n }\n\n c.set('token', token)\n\n // Check cache first\n const cached = await getCachedUser(token)\n if (cached) {\n c.set('user', cached)\n c.set('userId', cached.id)\n c.set('isAuth', true)\n return next()\n }\n\n // Verify JWT\n try {\n const jwks = await getJwks(jwksUri, jwksCacheTtl)\n const { payload } = await jose.jwtVerify(token, jwks, {\n audience: clientId,\n })\n\n const user = payloadToUser(payload)\n c.set('user', user)\n c.set('userId', user.id)\n c.set('isAuth', true)\n\n // Cache the result\n await cacheUser(token, user)\n } catch {\n // Invalid token - leave user as null\n }\n\n return next()\n }\n}\n\n/**\n * Require auth middleware - rejects unauthenticated requests\n *\n * @example\n * ```ts\n * import { Hono } from 'hono'\n * import { auth, requireAuth } from 'oauth.do/hono'\n *\n * const app = new Hono()\n * app.use('*', auth())\n * app.use('/api/*', requireAuth())\n *\n * app.get('/api/secret', (c) => {\n * return c.json({ secret: 'data', user: c.var.user })\n * })\n * ```\n */\nexport function requireAuth(options: RequireAuthOptions = {}): MiddlewareHandler {\n const { redirectTo, roles, permissions, ...authOptions } = options\n\n return async (c, next) => {\n // Run auth middleware first if not already done\n if (c.var.user === undefined) {\n await auth(authOptions)(c, async () => {})\n }\n\n if (!c.var.isAuth || !c.var.user) {\n if (redirectTo) {\n return c.redirect(redirectTo)\n }\n return c.json({ error: 'Authentication required' }, 401)\n }\n\n // Check roles (any of)\n if (roles?.length) {\n const userRoles = c.var.user.roles || []\n const hasRole = roles.some((r) => userRoles.includes(r))\n if (!hasRole) {\n return c.json({ error: 'Insufficient permissions' }, 403)\n }\n }\n\n // Check permissions (all of)\n if (permissions?.length) {\n const userPerms = c.var.user.permissions || []\n const hasAllPerms = permissions.every((p) => userPerms.includes(p))\n if (!hasAllPerms) {\n return c.json({ error: 'Insufficient permissions' }, 403)\n }\n }\n\n return next()\n }\n}\n\n/**\n * API key middleware - authenticates via API key header\n *\n * @example\n * ```ts\n * import { Hono } from 'hono'\n * import { apiKey } from 'oauth.do/hono'\n *\n * const app = new Hono()\n * app.use('/api/*', apiKey({\n * verify: async (key, c) => {\n * // Verify key against your database/service\n * const user = await verifyApiKey(key)\n * return user\n * }\n * }))\n * ```\n */\nexport function apiKey(options: ApiKeyOptions): MiddlewareHandler {\n const { headerName = 'X-API-Key', verify } = options\n\n return async (c, next) => {\n c.set('user', null)\n c.set('userId', null)\n c.set('isAuth', false)\n c.set('token', null)\n\n const key = c.req.header(headerName)\n if (!key) {\n return c.json({ error: 'API key required' }, 401)\n }\n\n const user = await verify(key, c)\n if (!user) {\n return c.json({ error: 'Invalid API key' }, 401)\n }\n\n c.set('user', user)\n c.set('userId', user.id)\n c.set('isAuth', true)\n c.set('token', key)\n\n return next()\n }\n}\n\n/**\n * Combined auth middleware - tries JWT first, then API key\n *\n * @example\n * ```ts\n * import { Hono } from 'hono'\n * import { combined } from 'oauth.do/hono'\n *\n * const app = new Hono()\n * app.use('/api/*', combined({\n * apiKey: {\n * verify: async (key) => verifyApiKey(key)\n * }\n * }))\n * ```\n */\nexport function combined(options: {\n auth?: AuthOptions\n apiKey?: ApiKeyOptions\n}): MiddlewareHandler {\n return async (c, next) => {\n // Try JWT auth first\n if (options.auth) {\n await auth(options.auth)(c, async () => {})\n if (c.var.isAuth) {\n return next()\n }\n }\n\n // Fall back to API key\n if (options.apiKey) {\n const key = c.req.header(options.apiKey.headerName || 'X-API-Key')\n if (key) {\n const user = await options.apiKey.verify(key, c)\n if (user) {\n c.set('user', user)\n c.set('userId', user.id)\n c.set('isAuth', true)\n c.set('token', key)\n return next()\n }\n }\n }\n\n return c.json({ error: 'Authentication required' }, 401)\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/session.ts","../src/session-hono.ts","../src/hono.ts"],"names":["combined","apiKey","getCookie"],"mappings":"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","file":"hono.js","sourcesContent":["/**\n * oauth.do/session - Cookie-based session management with AES-GCM encryption\n *\n * Secure session encoding/decoding using Web Crypto API.\n * Zero dependencies - works in all environments that support Web Crypto.\n *\n * @example\n * ```ts\n * import { encodeSession, decodeSession } from 'oauth.do/session'\n *\n * const session = { userId: 'user_123', accessToken: 'tok_abc' }\n * const encoded = await encodeSession(session, 'my-secret-key')\n * const decoded = await decodeSession(encoded, 'my-secret-key')\n * ```\n */\n\n// ─────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────\n\n/**\n * Session data stored in encrypted cookie\n */\nexport interface SessionData {\n userId: string\n organizationId?: string\n email?: string\n name?: string\n accessToken: string\n refreshToken?: string\n expiresAt?: number\n /** Extensible: apps can add custom fields */\n [key: string]: unknown\n}\n\n/**\n * Configuration for session management\n */\nexport interface SessionConfig {\n /** Cookie name (default: 'session') */\n cookieName: string\n /** Cookie max age in seconds (default: 604800 = 7 days) */\n cookieMaxAge: number\n /** Cookie secure flag (default: true) */\n cookieSecure: boolean\n /** Cookie SameSite attribute (default: 'lax') */\n cookieSameSite: 'strict' | 'lax' | 'none'\n /** Encryption secret (required in production) */\n secret: string\n}\n\n/**\n * Default session configuration\n */\nexport const defaultSessionConfig: SessionConfig = {\n cookieName: 'session',\n cookieMaxAge: 60 * 60 * 24 * 7, // 7 days\n cookieSecure: true,\n cookieSameSite: 'lax',\n secret: 'oauth-do-dev-secret-change-in-production',\n}\n\n// ─────────────────────────────────────────────────────────────────\n// AES-GCM Encryption\n// ─────────────────────────────────────────────────────────────────\n\nconst ALGORITHM = 'AES-GCM'\nconst IV_LENGTH = 12\nconst TAG_LENGTH = 128\n\n/**\n * Derive an AES-GCM encryption key from a secret string\n */\nasync function getEncryptionKey(secret: string): Promise<CryptoKey> {\n const encoder = new TextEncoder()\n return crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret.padEnd(32, '0').slice(0, 32)),\n { name: ALGORITHM },\n false,\n ['encrypt', 'decrypt']\n )\n}\n\n/**\n * Encode session data with AES-GCM encryption.\n * Format: base64(IV || ciphertext || auth tag)\n *\n * @param session - Session data to encrypt\n * @param secret - Encryption secret (min 16 chars recommended)\n * @returns Base64-encoded encrypted session string\n */\nexport async function encodeSession(session: SessionData, secret?: string): Promise<string> {\n const key = await getEncryptionKey(secret ?? defaultSessionConfig.secret)\n const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH))\n const encoder = new TextEncoder()\n const data = encoder.encode(JSON.stringify(session))\n\n const ciphertext = await crypto.subtle.encrypt(\n { name: ALGORITHM, iv, tagLength: TAG_LENGTH },\n key,\n data\n )\n\n // Combine IV + ciphertext (ciphertext includes auth tag)\n const combined = new Uint8Array(iv.length + ciphertext.byteLength)\n combined.set(iv, 0)\n combined.set(new Uint8Array(ciphertext), iv.length)\n\n return btoa(String.fromCharCode(...combined))\n}\n\n/**\n * Decode session data with AES-GCM decryption.\n * Returns null if decryption fails or data is invalid.\n *\n * @param encoded - Base64-encoded encrypted session string\n * @param secret - Encryption secret (must match the one used for encoding)\n * @returns Decoded session data or null\n */\nexport async function decodeSession(encoded: string, secret?: string): Promise<SessionData | null> {\n try {\n const key = await getEncryptionKey(secret ?? defaultSessionConfig.secret)\n const combined = Uint8Array.from(atob(encoded), (c) => c.charCodeAt(0))\n\n const iv = combined.slice(0, IV_LENGTH)\n const ciphertext = combined.slice(IV_LENGTH)\n\n const decrypted = await crypto.subtle.decrypt(\n { name: ALGORITHM, iv, tagLength: TAG_LENGTH },\n key,\n ciphertext\n )\n\n const decoder = new TextDecoder()\n const parsed: unknown = JSON.parse(decoder.decode(decrypted))\n\n if (!isValidSessionData(parsed)) {\n return null\n }\n\n return parsed\n } catch {\n return null\n }\n}\n\n/**\n * Validate that session data has the required structure\n */\nexport function isValidSessionData(data: unknown): data is SessionData {\n if (data === null || typeof data !== 'object') {\n return false\n }\n\n const session = data as Record<string, unknown>\n\n // Required fields\n if (typeof session.userId !== 'string' || session.userId.length === 0) {\n return false\n }\n if (typeof session.accessToken !== 'string' || session.accessToken.length === 0) {\n return false\n }\n\n // Optional fields type validation\n if (session.organizationId !== undefined && typeof session.organizationId !== 'string') {\n return false\n }\n if (session.email !== undefined && typeof session.email !== 'string') {\n return false\n }\n if (session.name !== undefined && typeof session.name !== 'string') {\n return false\n }\n if (session.refreshToken !== undefined && typeof session.refreshToken !== 'string') {\n return false\n }\n if (session.expiresAt !== undefined && typeof session.expiresAt !== 'number') {\n return false\n }\n\n return true\n}\n\n/**\n * Get session config from environment variables with defaults.\n *\n * Environment variables:\n * - SESSION_SECRET: Encryption secret\n * - SESSION_COOKIE_NAME: Cookie name\n * - SESSION_COOKIE_MAX_AGE: Cookie max age in seconds\n * - SESSION_COOKIE_SECURE: 'true' or 'false'\n * - SESSION_COOKIE_SAME_SITE: 'strict', 'lax', or 'none'\n */\nexport function getSessionConfig(env?: Record<string, string | undefined>): SessionConfig {\n const validSameSite = ['strict', 'lax', 'none'] as const\n\n let cookieSameSite: SessionConfig['cookieSameSite'] = defaultSessionConfig.cookieSameSite\n if (env?.SESSION_COOKIE_SAME_SITE) {\n const value = env.SESSION_COOKIE_SAME_SITE\n if (validSameSite.includes(value as typeof validSameSite[number])) {\n cookieSameSite = value as SessionConfig['cookieSameSite']\n }\n }\n\n let cookieMaxAge = defaultSessionConfig.cookieMaxAge\n if (env?.SESSION_COOKIE_MAX_AGE) {\n const parsed = parseInt(env.SESSION_COOKIE_MAX_AGE, 10)\n if (!Number.isNaN(parsed) && parsed > 0) {\n cookieMaxAge = parsed\n }\n }\n\n return {\n secret: env?.SESSION_SECRET ?? defaultSessionConfig.secret,\n cookieName: env?.SESSION_COOKIE_NAME ?? defaultSessionConfig.cookieName,\n cookieMaxAge,\n cookieSecure: env?.SESSION_COOKIE_SECURE !== 'false',\n cookieSameSite,\n }\n}\n","/**\n * oauth.do/session-hono - Hono middleware for cookie-based session auth\n *\n * Provides session-based authentication as an alternative to JWT middleware.\n * Uses AES-GCM encrypted cookies for secure, stateless sessions.\n *\n * @example\n * ```ts\n * import { Hono } from 'hono'\n * import { sessionAuth, requireSession, createOAuthRoutes } from 'oauth.do/hono'\n *\n * const app = new Hono()\n * app.use('*', sessionAuth())\n * app.route('/auth', createOAuthRoutes({\n * workosApiKey: env.WORKOS_API_KEY,\n * clientId: env.WORKOS_CLIENT_ID,\n * }))\n * ```\n */\n\nimport type { Context, MiddlewareHandler } from 'hono'\nimport { Hono } from 'hono'\nimport { getCookie, setCookie, deleteCookie } from 'hono/cookie'\nimport type { SessionData, SessionConfig } from './session'\nimport { encodeSession, decodeSession, defaultSessionConfig, getSessionConfig } from './session'\n\n// ─────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────\n\n/**\n * User info extracted from session\n */\nexport interface SessionUser {\n id: string\n email?: string\n name?: string\n organizationId?: string\n}\n\n// Extend Hono context with session variables\ndeclare module 'hono' {\n interface ContextVariableMap {\n session: SessionData | null\n sessionUser: SessionUser | null\n }\n}\n\n/**\n * Options for session auth middleware\n */\nexport interface SessionAuthOptions {\n /** Session configuration (cookie name, secret, etc.) */\n config?: Partial<SessionConfig>\n}\n\n/**\n * Options for creating OAuth routes\n */\nexport interface OAuthRoutesOptions {\n /** WorkOS API Key */\n workosApiKey?: string\n /** WorkOS Client ID */\n clientId?: string\n /** Session configuration */\n session?: Partial<SessionConfig>\n /** Base URL for OAuth redirects (derived from request if not set) */\n redirectBaseUrl?: string\n /** Path prefix for auth routes (default: '') */\n pathPrefix?: string\n /** Callback after successful login */\n onLogin?: (session: SessionData, c: Context) => void | Promise<void>\n /** Callback after logout */\n onLogout?: (c: Context) => void | Promise<void>\n /** Enable debug logging */\n debug?: boolean\n}\n\n/**\n * Environment bindings for session auth\n */\nexport interface SessionEnv {\n WORKOS_API_KEY?: string\n WORKOS_CLIENT_ID?: string\n SESSION_SECRET?: string\n SESSION_COOKIE_NAME?: string\n SESSION_COOKIE_MAX_AGE?: string\n SESSION_COOKIE_SECURE?: string\n SESSION_COOKIE_SAME_SITE?: string\n AUTH_REDIRECT_BASE_URL?: string\n DEBUG?: string\n}\n\n// ─────────────────────────────────────────────────────────────────\n// Cookie Helpers\n// ─────────────────────────────────────────────────────────────────\n\n/**\n * Set session cookie with encrypted session data\n */\nexport async function setSessionCookie(\n c: Context,\n session: SessionData,\n config: SessionConfig = defaultSessionConfig\n): Promise<void> {\n const encoded = await encodeSession(session, config.secret)\n setCookie(c, config.cookieName, encoded, {\n path: '/',\n httpOnly: true,\n secure: config.cookieSecure,\n sameSite: config.cookieSameSite === 'none' ? 'None' : config.cookieSameSite === 'strict' ? 'Strict' : 'Lax',\n maxAge: config.cookieMaxAge,\n })\n}\n\n/**\n * Clear session cookie\n */\nexport function clearSessionCookie(c: Context, config: SessionConfig = defaultSessionConfig): void {\n deleteCookie(c, config.cookieName, { path: '/' })\n}\n\n/**\n * Get session from cookie\n */\nexport async function getSessionFromCookie(\n c: Context,\n config: SessionConfig = defaultSessionConfig\n): Promise<SessionData | null> {\n const encoded = getCookie(c, config.cookieName)\n if (!encoded) return null\n return decodeSession(encoded, config.secret)\n}\n\n// ─────────────────────────────────────────────────────────────────\n// Middleware\n// ─────────────────────────────────────────────────────────────────\n\n/**\n * Session auth middleware - populates c.var.session and c.var.sessionUser\n *\n * Non-blocking: sets null if no session exists. Use requireSession() for guarded access.\n *\n * @example\n * ```ts\n * app.use('*', sessionAuth())\n * app.get('/me', (c) => {\n * if (!c.var.session) return c.json({ error: 'Not authenticated' }, 401)\n * return c.json(c.var.sessionUser)\n * })\n * ```\n */\nexport function sessionAuth(options: SessionAuthOptions = {}): MiddlewareHandler {\n return async (c, next) => {\n const env = (c.env ?? {}) as SessionEnv\n const config = { ...getSessionConfig(env as Record<string, string | undefined>), ...options.config }\n\n const session = await getSessionFromCookie(c, config)\n\n c.set('session', session)\n c.set('sessionUser', session ? {\n id: session.userId,\n email: session.email,\n name: session.name,\n organizationId: session.organizationId,\n } : null)\n\n await next()\n }\n}\n\n/**\n * Require session middleware - returns 401 if no valid session\n *\n * @example\n * ```ts\n * app.use('/api/*', requireSession())\n * ```\n */\nexport function requireSession(options: SessionAuthOptions = {}): MiddlewareHandler {\n return async (c, next) => {\n const env = (c.env ?? {}) as SessionEnv\n const config = { ...getSessionConfig(env as Record<string, string | undefined>), ...options.config }\n\n const session = await getSessionFromCookie(c, config)\n\n if (!session) {\n return c.json({ error: 'Unauthorized', message: 'Authentication required' }, 401)\n }\n\n // Check expiration\n if (session.expiresAt && Date.now() >= session.expiresAt) {\n clearSessionCookie(c, config)\n return c.json({ error: 'Unauthorized', message: 'Session expired' }, 401)\n }\n\n c.set('session', session)\n c.set('sessionUser', {\n id: session.userId,\n email: session.email,\n name: session.name,\n organizationId: session.organizationId,\n })\n\n await next()\n }\n}\n\n// ─────────────────────────────────────────────────────────────────\n// WorkOS Client\n// ─────────────────────────────────────────────────────────────────\n\n/**\n * Create a lightweight WorkOS client (fetch-based, no SDK dependency)\n */\nfunction createWorkOSClient(apiKey: string) {\n const baseUrl = 'https://api.workos.com'\n\n return {\n getAuthorizationUrl(options: {\n clientId: string\n redirectUri: string\n state?: string\n provider?: string\n }): string {\n const params = new URLSearchParams({\n client_id: options.clientId,\n redirect_uri: options.redirectUri,\n response_type: 'code',\n ...(options.state && { state: options.state }),\n ...(options.provider && { provider: options.provider }),\n })\n return `https://api.workos.com/sso/authorize?${params.toString()}`\n },\n\n async authenticateWithCode(options: {\n clientId: string\n code: string\n redirectUri: string\n }): Promise<{\n access_token: string\n refresh_token?: string\n expires_in?: number\n user: {\n id: string\n email: string\n first_name?: string\n last_name?: string\n organization_id?: string\n }\n }> {\n const response = await fetch(`${baseUrl}/user_management/authenticate`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n 'Authorization': `Bearer ${apiKey}`,\n },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: options.clientId,\n code: options.code,\n redirect_uri: options.redirectUri,\n }).toString(),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`WorkOS authentication failed: ${response.status} - ${error}`)\n }\n\n return response.json()\n },\n\n async refreshToken(options: {\n clientId: string\n refreshToken: string\n }): Promise<{\n access_token: string\n refresh_token?: string\n expires_in?: number\n }> {\n const response = await fetch(`${baseUrl}/user_management/authenticate`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n 'Authorization': `Bearer ${apiKey}`,\n },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: options.clientId,\n refresh_token: options.refreshToken,\n }).toString(),\n })\n\n if (!response.ok) {\n const error = await response.text()\n throw new Error(`Token refresh failed: ${response.status} - ${error}`)\n }\n\n return response.json()\n },\n }\n}\n\n// ─────────────────────────────────────────────────────────────────\n// OAuth Routes Factory\n// ─────────────────────────────────────────────────────────────────\n\n/**\n * Create mountable OAuth routes for login, callback, logout, me, and refresh.\n *\n * @example\n * ```ts\n * import { Hono } from 'hono'\n * import { createOAuthRoutes } from 'oauth.do/hono'\n *\n * const app = new Hono()\n * app.route('/auth', createOAuthRoutes({\n * workosApiKey: env.WORKOS_API_KEY,\n * clientId: env.WORKOS_CLIENT_ID,\n * session: { secret: env.SESSION_SECRET },\n * }))\n * ```\n *\n * Routes:\n * - GET /login - Redirect to WorkOS authorization\n * - GET /callback - Handle OAuth callback, set session cookie\n * - GET /logout - Clear cookie, redirect\n * - POST /logout - Clear cookie, JSON response\n * - GET /me - Return session user info\n * - POST /refresh - Refresh access token\n */\nexport function createOAuthRoutes(options: OAuthRoutesOptions = {}): Hono {\n const app = new Hono()\n\n // UTF-8 charset middleware\n app.use('*', async (c, next) => {\n await next()\n const contentType = c.res.headers.get('content-type')\n if (contentType?.includes('application/json') && !contentType.includes('charset')) {\n c.res.headers.set('content-type', 'application/json; charset=utf-8')\n }\n })\n\n /**\n * GET /login - Redirect to WorkOS authorization\n */\n app.get('/login', (c) => {\n const env = (c.env ?? {}) as SessionEnv\n const apiKey = options.workosApiKey ?? env.WORKOS_API_KEY\n const clientId = options.clientId ?? env.WORKOS_CLIENT_ID\n\n if (!apiKey) {\n return c.json({ error: 'Server configuration error', message: 'WORKOS_API_KEY not configured' }, 500)\n }\n if (!clientId) {\n return c.json({ error: 'Server configuration error', message: 'WORKOS_CLIENT_ID not configured' }, 500)\n }\n\n const workos = createWorkOSClient(apiKey)\n const url = new URL(c.req.url)\n const baseUrl = options.redirectBaseUrl ?? env.AUTH_REDIRECT_BASE_URL ?? `${url.protocol}//${url.host}`\n\n const intendedRedirect = c.req.query('redirect_uri') || '/'\n const provider = c.req.query('provider')\n const state = btoa(JSON.stringify({ redirect: intendedRedirect }))\n\n const authUrl = workos.getAuthorizationUrl({\n clientId,\n redirectUri: `${baseUrl}/auth/callback`,\n state,\n provider,\n })\n\n return c.redirect(authUrl)\n })\n\n /**\n * GET /callback - Handle OAuth callback\n */\n app.get('/callback', async (c) => {\n const env = (c.env ?? {}) as SessionEnv\n const apiKey = options.workosApiKey ?? env.WORKOS_API_KEY\n const clientId = options.clientId ?? env.WORKOS_CLIENT_ID\n const sessionConfig = { ...getSessionConfig(env as Record<string, string | undefined>), ...options.session }\n const debug = options.debug ?? env.DEBUG === 'true'\n\n if (!apiKey) {\n return c.json({ error: 'Server configuration error', message: 'WORKOS_API_KEY not configured' }, 500)\n }\n if (!clientId) {\n return c.json({ error: 'Server configuration error', message: 'WORKOS_CLIENT_ID not configured' }, 500)\n }\n\n const code = c.req.query('code')\n const state = c.req.query('state')\n const error = c.req.query('error')\n const errorDescription = c.req.query('error_description')\n\n if (error) {\n if (debug) console.error('[Auth] OAuth error:', error, errorDescription)\n return c.json({ error: 'Authentication failed', message: errorDescription || error }, 400)\n }\n\n if (!code) {\n return c.json({ error: 'Missing authorization code' }, 400)\n }\n\n const workos = createWorkOSClient(apiKey)\n const url = new URL(c.req.url)\n const baseUrl = options.redirectBaseUrl ?? env.AUTH_REDIRECT_BASE_URL ?? `${url.protocol}//${url.host}`\n\n try {\n const result = await workos.authenticateWithCode({\n clientId,\n code,\n redirectUri: `${baseUrl}/auth/callback`,\n })\n\n const session: SessionData = {\n userId: result.user.id,\n organizationId: result.user.organization_id,\n email: result.user.email,\n name: [result.user.first_name, result.user.last_name].filter(Boolean).join(' ') || undefined,\n accessToken: result.access_token,\n refreshToken: result.refresh_token,\n expiresAt: result.expires_in ? Date.now() + result.expires_in * 1000 : undefined,\n }\n\n await setSessionCookie(c, session, sessionConfig)\n await options.onLogin?.(session, c)\n\n let redirectTo = '/'\n if (state) {\n try {\n const stateData = JSON.parse(atob(state))\n redirectTo = stateData.redirect || '/'\n } catch {\n // Invalid state, use default\n }\n }\n\n // Prevent open redirects\n if (!redirectTo.startsWith('/')) {\n redirectTo = '/'\n }\n\n return c.redirect(redirectTo)\n } catch (err) {\n if (debug) console.error('[Auth] OAuth callback error:', err)\n return c.json({\n error: 'Authentication failed',\n message: err instanceof Error ? err.message : 'Unknown error',\n }, 500)\n }\n })\n\n /**\n * GET /logout - Clear session and redirect\n */\n app.get('/logout', async (c) => {\n const env = (c.env ?? {}) as SessionEnv\n const sessionConfig = { ...getSessionConfig(env as Record<string, string | undefined>), ...options.session }\n\n clearSessionCookie(c, sessionConfig)\n await options.onLogout?.(c)\n\n const redirectTo = c.req.query('redirect_uri') || '/'\n if (!redirectTo.startsWith('/')) {\n return c.redirect('/')\n }\n return c.redirect(redirectTo)\n })\n\n /**\n * POST /logout - JSON response logout\n */\n app.post('/logout', async (c) => {\n const env = (c.env ?? {}) as SessionEnv\n const sessionConfig = { ...getSessionConfig(env as Record<string, string | undefined>), ...options.session }\n\n clearSessionCookie(c, sessionConfig)\n await options.onLogout?.(c)\n\n return c.json({ success: true, message: 'Logged out successfully' })\n })\n\n /**\n * GET /me - Return session user info\n */\n app.get('/me', async (c) => {\n const env = (c.env ?? {}) as SessionEnv\n const sessionConfig = { ...getSessionConfig(env as Record<string, string | undefined>), ...options.session }\n\n const session = await getSessionFromCookie(c, sessionConfig)\n\n if (!session) {\n return c.json({ error: 'Unauthorized', message: 'Not authenticated' }, 401)\n }\n\n if (session.expiresAt && Date.now() >= session.expiresAt) {\n clearSessionCookie(c, sessionConfig)\n return c.json({ error: 'Unauthorized', message: 'Session expired' }, 401)\n }\n\n return c.json({\n id: session.userId,\n email: session.email,\n name: session.name,\n organizationId: session.organizationId,\n })\n })\n\n /**\n * POST /refresh - Refresh access token\n */\n app.post('/refresh', async (c) => {\n const env = (c.env ?? {}) as SessionEnv\n const apiKey = options.workosApiKey ?? env.WORKOS_API_KEY\n const clientId = options.clientId ?? env.WORKOS_CLIENT_ID\n const sessionConfig = { ...getSessionConfig(env as Record<string, string | undefined>), ...options.session }\n const debug = options.debug ?? env.DEBUG === 'true'\n\n if (!apiKey) {\n return c.json({ error: 'Server configuration error', message: 'WORKOS_API_KEY not configured' }, 500)\n }\n if (!clientId) {\n return c.json({ error: 'Server configuration error', message: 'WORKOS_CLIENT_ID not configured' }, 500)\n }\n\n const session = await getSessionFromCookie(c, sessionConfig)\n\n if (!session) {\n return c.json({ error: 'Unauthorized', message: 'Not authenticated' }, 401)\n }\n\n if (!session.refreshToken) {\n return c.json({ error: 'Cannot refresh', message: 'No refresh token available' }, 400)\n }\n\n const workos = createWorkOSClient(apiKey)\n\n try {\n const result = await workos.refreshToken({\n clientId,\n refreshToken: session.refreshToken,\n })\n\n const updatedSession: SessionData = {\n ...session,\n accessToken: result.access_token,\n refreshToken: result.refresh_token || session.refreshToken,\n expiresAt: result.expires_in ? Date.now() + result.expires_in * 1000 : undefined,\n }\n\n await setSessionCookie(c, updatedSession, sessionConfig)\n\n return c.json({ success: true, expiresAt: updatedSession.expiresAt })\n } catch (err) {\n if (debug) console.error('[Auth] Token refresh error:', err)\n clearSessionCookie(c, sessionConfig)\n return c.json({\n error: 'Refresh failed',\n message: err instanceof Error ? err.message : 'Unknown error',\n }, 401)\n }\n })\n\n return app\n}\n","/**\n * oauth.do/hono - Hono middleware for authentication\n *\n * Lightweight authentication middleware for Cloudflare Workers.\n * Uses jose for JWT verification - no heavy WorkOS SDK dependency.\n *\n * @packageDocumentation\n */\n\nimport type { Context, MiddlewareHandler } from 'hono'\nimport { getCookie } from 'hono/cookie'\nimport type { JWTPayload } from 'jose'\nimport * as jose from 'jose'\n\n// Cloudflare Workers Cache API type\ndeclare const caches: {\n default: Cache\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Types\n// ═══════════════════════════════════════════════════════════════════════════\n\nexport interface AuthUser {\n id: string\n email?: string\n name?: string\n organizationId?: string\n roles?: string[]\n permissions?: string[]\n metadata?: Record<string, unknown>\n}\n\nexport interface AuthVariables {\n user: AuthUser | null\n userId: string | null\n isAuth: boolean\n token: string | null\n}\n\ndeclare module 'hono' {\n interface ContextVariableMap extends AuthVariables {}\n}\n\nexport interface AuthOptions {\n /** Cookie name for JWT token (default: 'auth') */\n cookieName?: string\n /** Header name for Bearer token (default: 'Authorization') */\n headerName?: string\n /** WorkOS Client ID (default: oauth.do client ID) */\n clientId?: string\n /** JWKS URI for token verification (default: WorkOS JWKS) */\n jwksUri?: string\n /** Skip auth for certain paths */\n skip?: (c: Context) => boolean\n /** Cache duration for JWKS in seconds (default: 3600) */\n jwksCacheTtl?: number\n}\n\nexport interface RequireAuthOptions extends AuthOptions {\n /** Redirect to login page instead of 401 */\n redirectTo?: string\n /** Required roles (any of) */\n roles?: string[]\n /** Required permissions (all of) */\n permissions?: string[]\n}\n\nexport interface ApiKeyOptions {\n /** Header name (default: 'X-API-Key') */\n headerName?: string\n /** Verify function - return user if valid, null if not */\n verify: (key: string, c: Context) => Promise<AuthUser | null>\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Constants\n// ═══════════════════════════════════════════════════════════════════════════\n\nconst OAUTH_DO_CONFIG = {\n clientId: 'client_01JQYTRXK9ZPD8JPJTKDCRB656',\n jwksUri: 'https://api.workos.com/sso/jwks/client_01JQYTRXK9ZPD8JPJTKDCRB656',\n}\n\nconst TOKEN_CACHE_TTL = 5 * 60 // 5 minutes\nconst CACHE_URL_PREFIX = 'https://oauth.do/_cache/token/'\n\n// ═══════════════════════════════════════════════════════════════════════════\n// JWT Utilities\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Hash a token for cache key (avoids storing raw tokens in cache)\n */\nasync function hashToken(token: string): Promise<string> {\n const data = new TextEncoder().encode(token)\n const hashBuffer = await crypto.subtle.digest('SHA-256', data)\n return Array.from(new Uint8Array(hashBuffer))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Get cached user from Cache API\n */\nasync function getCachedUser(token: string): Promise<AuthUser | null> {\n try {\n const cache = caches.default\n const hash = await hashToken(token)\n const cacheKey = new Request(`${CACHE_URL_PREFIX}${hash}`)\n const cached = await cache.match(cacheKey)\n\n if (!cached) return null\n\n const data = await cached.json() as { user: AuthUser; expiresAt: number }\n if (data.expiresAt < Date.now()) return null\n\n return data.user\n } catch {\n return null\n }\n}\n\n/**\n * Cache user in Cache API\n */\nasync function cacheUser(token: string, user: AuthUser): Promise<void> {\n try {\n const cache = caches.default\n const hash = await hashToken(token)\n const cacheKey = new Request(`${CACHE_URL_PREFIX}${hash}`)\n const data = { user, expiresAt: Date.now() + TOKEN_CACHE_TTL * 1000 }\n const response = new Response(JSON.stringify(data), {\n headers: { 'Cache-Control': `max-age=${TOKEN_CACHE_TTL}` },\n })\n await cache.put(cacheKey, response)\n } catch {\n // Cache failures are non-fatal\n }\n}\n\n/**\n * Extract JWT from request (cookie or Bearer header)\n */\nfunction extractToken(c: Context, cookieName: string, headerName: string): string | null {\n // Try Bearer header first\n const authHeader = c.req.header(headerName)\n if (authHeader?.startsWith('Bearer ')) {\n return authHeader.slice(7)\n }\n\n // Try cookie\n const cookie = getCookie(c, cookieName)\n if (cookie) return cookie\n\n return null\n}\n\n/**\n * Convert JWT payload to AuthUser\n */\nfunction payloadToUser(payload: JWTPayload): AuthUser {\n return {\n id: payload.sub || '',\n email: payload.email as string | undefined,\n name: payload.name as string | undefined,\n organizationId: payload.org_id as string | undefined,\n roles: payload.roles as string[] | undefined,\n permissions: payload.permissions as string[] | undefined,\n metadata: payload.metadata as Record<string, unknown> | undefined,\n }\n}\n\n// JWKS cache (module-level, persists across requests)\nlet jwksCache: jose.JWTVerifyGetKey | null = null\nlet jwksCacheExpiry = 0\n\n/**\n * Get JWKS verifier with caching\n */\nasync function getJwks(jwksUri: string, cacheTtl: number): Promise<jose.JWTVerifyGetKey> {\n const now = Date.now()\n if (jwksCache && jwksCacheExpiry > now) {\n return jwksCache\n }\n\n jwksCache = jose.createRemoteJWKSet(new URL(jwksUri))\n jwksCacheExpiry = now + cacheTtl * 1000\n return jwksCache\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Middleware\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Auth middleware - populates c.var.user if authenticated\n *\n * Does NOT reject unauthenticated requests. Use requireAuth() for that.\n *\n * @example\n * ```ts\n * import { Hono } from 'hono'\n * import { auth } from 'oauth.do/hono'\n *\n * const app = new Hono()\n * app.use('*', auth())\n *\n * app.get('/api/me', (c) => {\n * if (!c.var.user) return c.json({ error: 'Not authenticated' }, 401)\n * return c.json(c.var.user)\n * })\n * ```\n */\nexport function auth(options: AuthOptions = {}): MiddlewareHandler {\n const {\n cookieName = 'auth',\n headerName = 'Authorization',\n clientId = OAUTH_DO_CONFIG.clientId,\n jwksUri = OAUTH_DO_CONFIG.jwksUri,\n skip,\n jwksCacheTtl = 3600,\n } = options\n\n return async (c, next) => {\n // Initialize variables\n c.set('user', null)\n c.set('userId', null)\n c.set('isAuth', false)\n c.set('token', null)\n\n // Skip if configured\n if (skip?.(c)) {\n return next()\n }\n\n const token = extractToken(c, cookieName, headerName)\n if (!token) {\n return next()\n }\n\n c.set('token', token)\n\n // Check cache first\n const cached = await getCachedUser(token)\n if (cached) {\n c.set('user', cached)\n c.set('userId', cached.id)\n c.set('isAuth', true)\n return next()\n }\n\n // Verify JWT\n try {\n const jwks = await getJwks(jwksUri, jwksCacheTtl)\n const { payload } = await jose.jwtVerify(token, jwks, {\n audience: clientId,\n })\n\n const user = payloadToUser(payload)\n c.set('user', user)\n c.set('userId', user.id)\n c.set('isAuth', true)\n\n // Cache the result\n await cacheUser(token, user)\n } catch {\n // Invalid token - leave user as null\n }\n\n return next()\n }\n}\n\n/**\n * Require auth middleware - rejects unauthenticated requests\n *\n * @example\n * ```ts\n * import { Hono } from 'hono'\n * import { auth, requireAuth } from 'oauth.do/hono'\n *\n * const app = new Hono()\n * app.use('*', auth())\n * app.use('/api/*', requireAuth())\n *\n * app.get('/api/secret', (c) => {\n * return c.json({ secret: 'data', user: c.var.user })\n * })\n * ```\n */\nexport function requireAuth(options: RequireAuthOptions = {}): MiddlewareHandler {\n const { redirectTo, roles, permissions, ...authOptions } = options\n\n return async (c, next) => {\n // Run auth middleware first if not already done\n if (c.var.user === undefined) {\n await auth(authOptions)(c, async () => {})\n }\n\n if (!c.var.isAuth || !c.var.user) {\n if (redirectTo) {\n return c.redirect(redirectTo)\n }\n return c.json({ error: 'Authentication required' }, 401)\n }\n\n // Check roles (any of)\n if (roles?.length) {\n const userRoles = c.var.user.roles || []\n const hasRole = roles.some((r) => userRoles.includes(r))\n if (!hasRole) {\n return c.json({ error: 'Insufficient permissions' }, 403)\n }\n }\n\n // Check permissions (all of)\n if (permissions?.length) {\n const userPerms = c.var.user.permissions || []\n const hasAllPerms = permissions.every((p) => userPerms.includes(p))\n if (!hasAllPerms) {\n return c.json({ error: 'Insufficient permissions' }, 403)\n }\n }\n\n return next()\n }\n}\n\n/**\n * API key middleware - authenticates via API key header\n *\n * @example\n * ```ts\n * import { Hono } from 'hono'\n * import { apiKey } from 'oauth.do/hono'\n *\n * const app = new Hono()\n * app.use('/api/*', apiKey({\n * verify: async (key, c) => {\n * // Verify key against your database/service\n * const user = await verifyApiKey(key)\n * return user\n * }\n * }))\n * ```\n */\nexport function apiKey(options: ApiKeyOptions): MiddlewareHandler {\n const { headerName = 'X-API-Key', verify } = options\n\n return async (c, next) => {\n c.set('user', null)\n c.set('userId', null)\n c.set('isAuth', false)\n c.set('token', null)\n\n const key = c.req.header(headerName)\n if (!key) {\n return c.json({ error: 'API key required' }, 401)\n }\n\n const user = await verify(key, c)\n if (!user) {\n return c.json({ error: 'Invalid API key' }, 401)\n }\n\n c.set('user', user)\n c.set('userId', user.id)\n c.set('isAuth', true)\n c.set('token', key)\n\n return next()\n }\n}\n\n/**\n * Combined auth middleware - tries JWT first, then API key\n *\n * @example\n * ```ts\n * import { Hono } from 'hono'\n * import { combined } from 'oauth.do/hono'\n *\n * const app = new Hono()\n * app.use('/api/*', combined({\n * apiKey: {\n * verify: async (key) => verifyApiKey(key)\n * }\n * }))\n * ```\n */\n// ═══════════════════════════════════════════════════════════════════════════\n// Session Auth Re-exports\n// ═══════════════════════════════════════════════════════════════════════════\n\nexport { sessionAuth, requireSession, createOAuthRoutes } from './session-hono'\nexport type { SessionUser, SessionAuthOptions, OAuthRoutesOptions, SessionEnv } from './session-hono'\nexport { encodeSession, decodeSession, getSessionConfig } from './session'\nexport type { SessionData, SessionConfig } from './session'\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Combined Auth\n// ═══════════════════════════════════════════════════════════════════════════\n\nexport function combined(options: {\n auth?: AuthOptions\n apiKey?: ApiKeyOptions\n}): MiddlewareHandler {\n return async (c, next) => {\n // Try JWT auth first\n if (options.auth) {\n await auth(options.auth)(c, async () => {})\n if (c.var.isAuth) {\n return next()\n }\n }\n\n // Fall back to API key\n if (options.apiKey) {\n const key = c.req.header(options.apiKey.headerName || 'X-API-Key')\n if (key) {\n const user = await options.apiKey.verify(key, c)\n if (user) {\n c.set('user', user)\n c.set('userId', user.id)\n c.set('isAuth', true)\n c.set('token', key)\n return next()\n }\n }\n }\n\n return c.json({ error: 'Authentication required' }, 401)\n }\n}\n"]}