oauth.do 0.1.15 → 0.2.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 +21 -0
- package/README.md +231 -6
- package/bin/duckdb-auth +71 -0
- package/dist/cli.js +125 -329
- package/dist/cli.js.map +1 -1
- package/dist/hono.d.ts +137 -0
- package/dist/hono.js +198 -0
- package/dist/hono.js.map +1 -0
- package/dist/index.d.ts +5 -89
- package/dist/index.js +24 -24
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +2 -1
- package/dist/node.js +108 -73
- package/dist/node.js.map +1 -1
- package/dist/react.d.ts +200 -0
- package/dist/react.js +67 -0
- package/dist/react.js.map +1 -0
- package/dist/types-export.d.ts +90 -0
- package/dist/types-export.js +3 -0
- package/dist/types-export.js.map +1 -0
- package/package.json +79 -9
package/dist/hono.js
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { getCookie } from 'hono/cookie';
|
|
2
|
+
import * as jose from 'jose';
|
|
3
|
+
|
|
4
|
+
// src/hono.ts
|
|
5
|
+
var OAUTH_DO_CONFIG = {
|
|
6
|
+
clientId: "client_01JQYTRXK9ZPD8JPJTKDCRB656",
|
|
7
|
+
jwksUri: "https://api.workos.com/sso/jwks/client_01JQYTRXK9ZPD8JPJTKDCRB656"
|
|
8
|
+
};
|
|
9
|
+
var TOKEN_CACHE_TTL = 5 * 60;
|
|
10
|
+
var CACHE_URL_PREFIX = "https://oauth.do/_cache/token/";
|
|
11
|
+
async function hashToken(token) {
|
|
12
|
+
const data = new TextEncoder().encode(token);
|
|
13
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
14
|
+
return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
15
|
+
}
|
|
16
|
+
async function getCachedUser(token) {
|
|
17
|
+
try {
|
|
18
|
+
const cache = caches.default;
|
|
19
|
+
const hash = await hashToken(token);
|
|
20
|
+
const cacheKey = new Request(`${CACHE_URL_PREFIX}${hash}`);
|
|
21
|
+
const cached = await cache.match(cacheKey);
|
|
22
|
+
if (!cached) return null;
|
|
23
|
+
const data = await cached.json();
|
|
24
|
+
if (data.expiresAt < Date.now()) return null;
|
|
25
|
+
return data.user;
|
|
26
|
+
} catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function cacheUser(token, user) {
|
|
31
|
+
try {
|
|
32
|
+
const cache = caches.default;
|
|
33
|
+
const hash = await hashToken(token);
|
|
34
|
+
const cacheKey = new Request(`${CACHE_URL_PREFIX}${hash}`);
|
|
35
|
+
const data = { user, expiresAt: Date.now() + TOKEN_CACHE_TTL * 1e3 };
|
|
36
|
+
const response = new Response(JSON.stringify(data), {
|
|
37
|
+
headers: { "Cache-Control": `max-age=${TOKEN_CACHE_TTL}` }
|
|
38
|
+
});
|
|
39
|
+
await cache.put(cacheKey, response);
|
|
40
|
+
} catch {
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function extractToken(c, cookieName, headerName) {
|
|
44
|
+
const authHeader = c.req.header(headerName);
|
|
45
|
+
if (authHeader?.startsWith("Bearer ")) {
|
|
46
|
+
return authHeader.slice(7);
|
|
47
|
+
}
|
|
48
|
+
const cookie = getCookie(c, cookieName);
|
|
49
|
+
if (cookie) return cookie;
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
function payloadToUser(payload) {
|
|
53
|
+
return {
|
|
54
|
+
id: payload.sub || "",
|
|
55
|
+
email: payload.email,
|
|
56
|
+
name: payload.name,
|
|
57
|
+
organizationId: payload.org_id,
|
|
58
|
+
roles: payload.roles,
|
|
59
|
+
permissions: payload.permissions,
|
|
60
|
+
metadata: payload.metadata
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
var jwksCache = null;
|
|
64
|
+
var jwksCacheExpiry = 0;
|
|
65
|
+
async function getJwks(jwksUri, cacheTtl) {
|
|
66
|
+
const now = Date.now();
|
|
67
|
+
if (jwksCache && jwksCacheExpiry > now) {
|
|
68
|
+
return jwksCache;
|
|
69
|
+
}
|
|
70
|
+
jwksCache = jose.createRemoteJWKSet(new URL(jwksUri));
|
|
71
|
+
jwksCacheExpiry = now + cacheTtl * 1e3;
|
|
72
|
+
return jwksCache;
|
|
73
|
+
}
|
|
74
|
+
function auth(options = {}) {
|
|
75
|
+
const {
|
|
76
|
+
cookieName = "auth",
|
|
77
|
+
headerName = "Authorization",
|
|
78
|
+
clientId = OAUTH_DO_CONFIG.clientId,
|
|
79
|
+
jwksUri = OAUTH_DO_CONFIG.jwksUri,
|
|
80
|
+
skip,
|
|
81
|
+
jwksCacheTtl = 3600
|
|
82
|
+
} = options;
|
|
83
|
+
return async (c, next) => {
|
|
84
|
+
c.set("user", null);
|
|
85
|
+
c.set("userId", null);
|
|
86
|
+
c.set("isAuth", false);
|
|
87
|
+
c.set("token", null);
|
|
88
|
+
if (skip?.(c)) {
|
|
89
|
+
return next();
|
|
90
|
+
}
|
|
91
|
+
const token = extractToken(c, cookieName, headerName);
|
|
92
|
+
if (!token) {
|
|
93
|
+
return next();
|
|
94
|
+
}
|
|
95
|
+
c.set("token", token);
|
|
96
|
+
const cached = await getCachedUser(token);
|
|
97
|
+
if (cached) {
|
|
98
|
+
c.set("user", cached);
|
|
99
|
+
c.set("userId", cached.id);
|
|
100
|
+
c.set("isAuth", true);
|
|
101
|
+
return next();
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
const jwks = await getJwks(jwksUri, jwksCacheTtl);
|
|
105
|
+
const { payload } = await jose.jwtVerify(token, jwks, {
|
|
106
|
+
audience: clientId
|
|
107
|
+
});
|
|
108
|
+
const user = payloadToUser(payload);
|
|
109
|
+
c.set("user", user);
|
|
110
|
+
c.set("userId", user.id);
|
|
111
|
+
c.set("isAuth", true);
|
|
112
|
+
await cacheUser(token, user);
|
|
113
|
+
} catch {
|
|
114
|
+
}
|
|
115
|
+
return next();
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function requireAuth(options = {}) {
|
|
119
|
+
const { redirectTo, roles, permissions, ...authOptions } = options;
|
|
120
|
+
return async (c, next) => {
|
|
121
|
+
if (c.var.user === void 0) {
|
|
122
|
+
await auth(authOptions)(c, async () => {
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
if (!c.var.isAuth || !c.var.user) {
|
|
126
|
+
if (redirectTo) {
|
|
127
|
+
return c.redirect(redirectTo);
|
|
128
|
+
}
|
|
129
|
+
return c.json({ error: "Authentication required" }, 401);
|
|
130
|
+
}
|
|
131
|
+
if (roles?.length) {
|
|
132
|
+
const userRoles = c.var.user.roles || [];
|
|
133
|
+
const hasRole = roles.some((r) => userRoles.includes(r));
|
|
134
|
+
if (!hasRole) {
|
|
135
|
+
return c.json({ error: "Insufficient permissions" }, 403);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (permissions?.length) {
|
|
139
|
+
const userPerms = c.var.user.permissions || [];
|
|
140
|
+
const hasAllPerms = permissions.every((p) => userPerms.includes(p));
|
|
141
|
+
if (!hasAllPerms) {
|
|
142
|
+
return c.json({ error: "Insufficient permissions" }, 403);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return next();
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function apiKey(options) {
|
|
149
|
+
const { headerName = "X-API-Key", verify } = options;
|
|
150
|
+
return async (c, next) => {
|
|
151
|
+
c.set("user", null);
|
|
152
|
+
c.set("userId", null);
|
|
153
|
+
c.set("isAuth", false);
|
|
154
|
+
c.set("token", null);
|
|
155
|
+
const key = c.req.header(headerName);
|
|
156
|
+
if (!key) {
|
|
157
|
+
return c.json({ error: "API key required" }, 401);
|
|
158
|
+
}
|
|
159
|
+
const user = await verify(key, c);
|
|
160
|
+
if (!user) {
|
|
161
|
+
return c.json({ error: "Invalid API key" }, 401);
|
|
162
|
+
}
|
|
163
|
+
c.set("user", user);
|
|
164
|
+
c.set("userId", user.id);
|
|
165
|
+
c.set("isAuth", true);
|
|
166
|
+
c.set("token", key);
|
|
167
|
+
return next();
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function combined(options) {
|
|
171
|
+
return async (c, next) => {
|
|
172
|
+
if (options.auth) {
|
|
173
|
+
await auth(options.auth)(c, async () => {
|
|
174
|
+
});
|
|
175
|
+
if (c.var.isAuth) {
|
|
176
|
+
return next();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (options.apiKey) {
|
|
180
|
+
const key = c.req.header(options.apiKey.headerName || "X-API-Key");
|
|
181
|
+
if (key) {
|
|
182
|
+
const user = await options.apiKey.verify(key, c);
|
|
183
|
+
if (user) {
|
|
184
|
+
c.set("user", user);
|
|
185
|
+
c.set("userId", user.id);
|
|
186
|
+
c.set("isAuth", true);
|
|
187
|
+
c.set("token", key);
|
|
188
|
+
return next();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return c.json({ error: "Authentication required" }, 401);
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export { apiKey, auth, combined, requireAuth };
|
|
197
|
+
//# sourceMappingURL=hono.js.map
|
|
198
|
+
//# sourceMappingURL=hono.js.map
|
package/dist/hono.js.map
ADDED
|
@@ -0,0 +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"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,91 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*/
|
|
4
|
-
interface OAuthConfig {
|
|
5
|
-
/**
|
|
6
|
-
* Base URL for API endpoints
|
|
7
|
-
* @default 'https://apis.do'
|
|
8
|
-
*/
|
|
9
|
-
apiUrl?: string;
|
|
10
|
-
/**
|
|
11
|
-
* Client ID for OAuth flow
|
|
12
|
-
*/
|
|
13
|
-
clientId?: string;
|
|
14
|
-
/**
|
|
15
|
-
* AuthKit domain for device authorization
|
|
16
|
-
* @default 'login.oauth.do'
|
|
17
|
-
*/
|
|
18
|
-
authKitDomain?: string;
|
|
19
|
-
/**
|
|
20
|
-
* Custom fetch implementation
|
|
21
|
-
*/
|
|
22
|
-
fetch?: typeof fetch;
|
|
23
|
-
/**
|
|
24
|
-
* Custom path for token storage
|
|
25
|
-
* Supports ~ for home directory (e.g., '~/.studio/tokens.json')
|
|
26
|
-
* @default '~/.oauth.do/token'
|
|
27
|
-
*/
|
|
28
|
-
storagePath?: string;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* User information returned from auth endpoints
|
|
32
|
-
*/
|
|
33
|
-
interface User {
|
|
34
|
-
id: string;
|
|
35
|
-
email?: string;
|
|
36
|
-
name?: string;
|
|
37
|
-
[key: string]: any;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Authentication result
|
|
41
|
-
*/
|
|
42
|
-
interface AuthResult {
|
|
43
|
-
user: User | null;
|
|
44
|
-
token?: string;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Device authorization response
|
|
48
|
-
*/
|
|
49
|
-
interface DeviceAuthorizationResponse {
|
|
50
|
-
device_code: string;
|
|
51
|
-
user_code: string;
|
|
52
|
-
verification_uri: string;
|
|
53
|
-
verification_uri_complete: string;
|
|
54
|
-
expires_in: number;
|
|
55
|
-
interval: number;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Token response
|
|
59
|
-
*/
|
|
60
|
-
interface TokenResponse {
|
|
61
|
-
access_token: string;
|
|
62
|
-
refresh_token?: string;
|
|
63
|
-
token_type: string;
|
|
64
|
-
expires_in?: number;
|
|
65
|
-
user?: User;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Token polling error types
|
|
69
|
-
*/
|
|
70
|
-
type TokenError = 'authorization_pending' | 'slow_down' | 'access_denied' | 'expired_token' | 'unknown';
|
|
71
|
-
/**
|
|
72
|
-
* Stored token data including refresh token and expiration
|
|
73
|
-
*/
|
|
74
|
-
interface StoredTokenData {
|
|
75
|
-
accessToken: string;
|
|
76
|
-
refreshToken?: string;
|
|
77
|
-
expiresAt?: number;
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Token storage interface
|
|
81
|
-
*/
|
|
82
|
-
interface TokenStorage {
|
|
83
|
-
getToken(): Promise<string | null>;
|
|
84
|
-
setToken(token: string): Promise<void>;
|
|
85
|
-
removeToken(): Promise<void>;
|
|
86
|
-
getTokenData?(): Promise<StoredTokenData | null>;
|
|
87
|
-
setTokenData?(data: StoredTokenData): Promise<void>;
|
|
88
|
-
}
|
|
1
|
+
import { AuthResult, OAuthConfig, DeviceAuthorizationResponse, TokenResponse, TokenStorage, StoredTokenData } from './types-export.js';
|
|
2
|
+
export { TokenError, User } from './types-export.js';
|
|
89
3
|
|
|
90
4
|
/**
|
|
91
5
|
* Get current authenticated user
|
|
@@ -460,6 +374,8 @@ interface LoginResult {
|
|
|
460
374
|
* Get existing token or perform device flow login
|
|
461
375
|
* Handles browser launch and token storage automatically
|
|
462
376
|
* Automatically refreshes expired tokens if refresh_token is available
|
|
377
|
+
*
|
|
378
|
+
* Uses singleton pattern to prevent multiple concurrent login/refresh attempts
|
|
463
379
|
*/
|
|
464
380
|
declare function ensureLoggedIn(options?: LoginOptions): Promise<LoginResult>;
|
|
465
381
|
/**
|
|
@@ -471,4 +387,4 @@ declare function forceLogin(options?: LoginOptions): Promise<LoginResult>;
|
|
|
471
387
|
*/
|
|
472
388
|
declare function ensureLoggedOut(options?: LoginOptions): Promise<void>;
|
|
473
389
|
|
|
474
|
-
export { type AuthProvider,
|
|
390
|
+
export { type AuthProvider, AuthResult, CompositeTokenStorage, DeviceAuthorizationResponse, FileTokenStorage, type GitHubDeviceAuthResponse, type GitHubDeviceFlowOptions, type GitHubTokenResponse, type GitHubUser, KeychainTokenStorage, LocalStorageTokenStorage, type LoginOptions, type LoginResult, MemoryTokenStorage, OAuthConfig, type OAuthProvider, SecureFileTokenStorage, TokenResponse, TokenStorage, ensureLoggedOut as a, auth, authorizeDevice, buildAuthUrl, configure, createSecureStorage, ensureLoggedIn as e, forceLogin as f, getConfig, getGitHubUser, getToken, getUser, isAuthenticated, login, logout, pollForTokens, pollGitHubDeviceFlow, startGitHubDeviceFlow };
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,17 @@ var __export = (target, all) => {
|
|
|
8
8
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
// src/utils.ts
|
|
12
|
+
function getEnv(key) {
|
|
13
|
+
if (globalThis[key]) return globalThis[key];
|
|
14
|
+
if (typeof process !== "undefined" && process.env?.[key]) return process.env[key];
|
|
15
|
+
return void 0;
|
|
16
|
+
}
|
|
17
|
+
var init_utils = __esm({
|
|
18
|
+
"src/utils.ts"() {
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
11
22
|
// src/storage.ts
|
|
12
23
|
var storage_exports = {};
|
|
13
24
|
__export(storage_exports, {
|
|
@@ -22,10 +33,6 @@ __export(storage_exports, {
|
|
|
22
33
|
function isNode() {
|
|
23
34
|
return typeof process !== "undefined" && process.versions != null && process.versions.node != null;
|
|
24
35
|
}
|
|
25
|
-
function getEnv2(key) {
|
|
26
|
-
if (typeof process !== "undefined" && process.env?.[key]) return process.env[key];
|
|
27
|
-
return void 0;
|
|
28
|
-
}
|
|
29
36
|
function createSecureStorage(storagePath) {
|
|
30
37
|
if (isNode()) {
|
|
31
38
|
return new SecureFileTokenStorage(storagePath);
|
|
@@ -38,6 +45,7 @@ function createSecureStorage(storagePath) {
|
|
|
38
45
|
var KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT, KeychainTokenStorage, SecureFileTokenStorage, FileTokenStorage, MemoryTokenStorage, LocalStorageTokenStorage, CompositeTokenStorage;
|
|
39
46
|
var init_storage = __esm({
|
|
40
47
|
"src/storage.ts"() {
|
|
48
|
+
init_utils();
|
|
41
49
|
KEYCHAIN_SERVICE = "oauth.do";
|
|
42
50
|
KEYCHAIN_ACCOUNT = "access_token";
|
|
43
51
|
KeychainTokenStorage = class {
|
|
@@ -57,7 +65,7 @@ var init_storage = __esm({
|
|
|
57
65
|
const keytarModule = imported.default || imported;
|
|
58
66
|
this.keytar = keytarModule;
|
|
59
67
|
if (typeof this.keytar.getPassword !== "function") {
|
|
60
|
-
if (
|
|
68
|
+
if (getEnv("DEBUG")) {
|
|
61
69
|
console.warn("Keytar module loaded but getPassword is not a function:", Object.keys(this.keytar));
|
|
62
70
|
}
|
|
63
71
|
this.keytar = null;
|
|
@@ -65,7 +73,7 @@ var init_storage = __esm({
|
|
|
65
73
|
}
|
|
66
74
|
return this.keytar;
|
|
67
75
|
} catch (error) {
|
|
68
|
-
if (
|
|
76
|
+
if (getEnv("DEBUG")) {
|
|
69
77
|
console.warn("Keychain storage not available:", error);
|
|
70
78
|
}
|
|
71
79
|
return null;
|
|
@@ -80,7 +88,7 @@ var init_storage = __esm({
|
|
|
80
88
|
const token = await keytar.getPassword(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT);
|
|
81
89
|
return token;
|
|
82
90
|
} catch (error) {
|
|
83
|
-
if (
|
|
91
|
+
if (getEnv("DEBUG")) {
|
|
84
92
|
console.warn("Failed to get token from keychain:", error);
|
|
85
93
|
}
|
|
86
94
|
return null;
|
|
@@ -122,7 +130,7 @@ var init_storage = __esm({
|
|
|
122
130
|
await keytar.getPassword(KEYCHAIN_SERVICE, "__test__");
|
|
123
131
|
return true;
|
|
124
132
|
} catch (error) {
|
|
125
|
-
if (
|
|
133
|
+
if (getEnv("DEBUG")) {
|
|
126
134
|
console.warn("Keychain not available:", error);
|
|
127
135
|
}
|
|
128
136
|
return false;
|
|
@@ -167,7 +175,7 @@ var init_storage = __esm({
|
|
|
167
175
|
const fs = await import('fs/promises');
|
|
168
176
|
const stats = await fs.stat(this.tokenPath);
|
|
169
177
|
const mode = stats.mode & 511;
|
|
170
|
-
if (mode !== 384 &&
|
|
178
|
+
if (mode !== 384 && getEnv("DEBUG")) {
|
|
171
179
|
console.warn(
|
|
172
180
|
`Warning: Token file has insecure permissions (${mode.toString(8)}). Expected 600. Run: chmod 600 ${this.tokenPath}`
|
|
173
181
|
);
|
|
@@ -346,7 +354,7 @@ var init_storage = __esm({
|
|
|
346
354
|
try {
|
|
347
355
|
await this.keychainStorage.setToken(fileToken);
|
|
348
356
|
await this.fileStorage.removeToken();
|
|
349
|
-
if (
|
|
357
|
+
if (getEnv("DEBUG")) {
|
|
350
358
|
console.log("Migrated token from file to keychain");
|
|
351
359
|
}
|
|
352
360
|
} catch {
|
|
@@ -377,11 +385,7 @@ var init_storage = __esm({
|
|
|
377
385
|
});
|
|
378
386
|
|
|
379
387
|
// src/config.ts
|
|
380
|
-
|
|
381
|
-
if (globalThis[key]) return globalThis[key];
|
|
382
|
-
if (typeof process !== "undefined" && process.env?.[key]) return process.env[key];
|
|
383
|
-
return void 0;
|
|
384
|
-
}
|
|
388
|
+
init_utils();
|
|
385
389
|
var globalConfig = {
|
|
386
390
|
apiUrl: getEnv("OAUTH_API_URL") || getEnv("API_URL") || "https://apis.do",
|
|
387
391
|
clientId: getEnv("OAUTH_CLIENT_ID") || "client_01JQYTRXK9ZPD8JPJTKDCRB656",
|
|
@@ -400,6 +404,7 @@ function getConfig() {
|
|
|
400
404
|
}
|
|
401
405
|
|
|
402
406
|
// src/auth.ts
|
|
407
|
+
init_utils();
|
|
403
408
|
async function resolveSecret(value) {
|
|
404
409
|
if (!value) return null;
|
|
405
410
|
if (typeof value === "string") return value;
|
|
@@ -408,14 +413,9 @@ async function resolveSecret(value) {
|
|
|
408
413
|
}
|
|
409
414
|
return null;
|
|
410
415
|
}
|
|
411
|
-
function getEnv3(key) {
|
|
412
|
-
if (globalThis[key]) return globalThis[key];
|
|
413
|
-
if (typeof process !== "undefined" && process.env?.[key]) return process.env[key];
|
|
414
|
-
return void 0;
|
|
415
|
-
}
|
|
416
416
|
async function getUser(token) {
|
|
417
417
|
const config = getConfig();
|
|
418
|
-
const authToken = token ||
|
|
418
|
+
const authToken = token || getEnv("DO_TOKEN") || "";
|
|
419
419
|
if (!authToken) {
|
|
420
420
|
return { user: null };
|
|
421
421
|
}
|
|
@@ -462,7 +462,7 @@ async function login(credentials) {
|
|
|
462
462
|
}
|
|
463
463
|
async function logout(token) {
|
|
464
464
|
const config = getConfig();
|
|
465
|
-
const authToken = token ||
|
|
465
|
+
const authToken = token || getEnv("DO_TOKEN") || "";
|
|
466
466
|
if (!authToken) {
|
|
467
467
|
return;
|
|
468
468
|
}
|
|
@@ -487,9 +487,9 @@ function isTokenExpired(expiresAt) {
|
|
|
487
487
|
return Date.now() >= expiresAt - REFRESH_BUFFER_MS;
|
|
488
488
|
}
|
|
489
489
|
async function getToken() {
|
|
490
|
-
const adminToken =
|
|
490
|
+
const adminToken = getEnv("DO_ADMIN_TOKEN");
|
|
491
491
|
if (adminToken) return adminToken;
|
|
492
|
-
const doToken =
|
|
492
|
+
const doToken = getEnv("DO_TOKEN");
|
|
493
493
|
if (doToken) return doToken;
|
|
494
494
|
try {
|
|
495
495
|
const { env } = await import('cloudflare:workers');
|