@multiplatform.one/auth 7.7.2
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 +201 -0
- package/README.md +49 -0
- package/dist/cjs/accessTokenRefresh.cjs +70 -0
- package/dist/cjs/accessTokenRefresh.native.js +78 -0
- package/dist/cjs/accessTokenRefresh.native.js.map +1 -0
- package/dist/cjs/index.cjs +369 -0
- package/dist/cjs/index.native.js +411 -0
- package/dist/cjs/index.native.js.map +1 -0
- package/dist/esm/accessTokenRefresh.mjs +40 -0
- package/dist/esm/accessTokenRefresh.mjs.map +1 -0
- package/dist/esm/accessTokenRefresh.native.js +45 -0
- package/dist/esm/accessTokenRefresh.native.js.map +1 -0
- package/dist/esm/index.mjs +336 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/index.native.js +375 -0
- package/dist/esm/index.native.js.map +1 -0
- package/dist/jsx/accessTokenRefresh.mjs +40 -0
- package/dist/jsx/accessTokenRefresh.mjs.map +1 -0
- package/dist/jsx/accessTokenRefresh.native.js +78 -0
- package/dist/jsx/accessTokenRefresh.native.js.map +1 -0
- package/dist/jsx/index.js +336 -0
- package/dist/jsx/index.js.map +1 -0
- package/dist/jsx/index.mjs +336 -0
- package/dist/jsx/index.mjs.map +1 -0
- package/dist/jsx/index.native.js +411 -0
- package/dist/jsx/index.native.js.map +1 -0
- package/package.json +78 -0
- package/src/accessTokenRefresh.ts +80 -0
- package/src/index.ts +665 -0
- package/types/accessTokenRefresh.d.ts +45 -0
- package/types/accessTokenRefresh.d.ts.map +1 -0
- package/types/index.d.ts +108 -0
- package/types/index.d.ts.map +1 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all) __defProp(target, name, {
|
|
7
|
+
get: all[name],
|
|
8
|
+
enumerable: true
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
14
|
+
get: () => from[key],
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
|
|
21
|
+
value: true
|
|
22
|
+
}), mod);
|
|
23
|
+
var index_exports = {};
|
|
24
|
+
__export(index_exports, {
|
|
25
|
+
ACCESS_TOKEN_RETRY_DELAYS_MS: () => import_accessTokenRefresh2.ACCESS_TOKEN_RETRY_DELAYS_MS,
|
|
26
|
+
FAILED_TO_GET_ACCESS_TOKEN: () => import_accessTokenRefresh2.FAILED_TO_GET_ACCESS_TOKEN,
|
|
27
|
+
TOKEN_REFRESH_UNAVAILABLE: () => import_accessTokenRefresh2.TOKEN_REFRESH_UNAVAILABLE,
|
|
28
|
+
classifyAccessTokenResponse: () => import_accessTokenRefresh2.classifyAccessTokenResponse,
|
|
29
|
+
createAuth: () => createAuth,
|
|
30
|
+
createAuthRouteHandler: () => createAuthRouteHandler,
|
|
31
|
+
createSessionHelpers: () => createSessionHelpers,
|
|
32
|
+
retryWhileTransient: () => import_accessTokenRefresh2.retryWhileTransient,
|
|
33
|
+
watchDocumentVisible: () => import_accessTokenRefresh2.watchDocumentVisible
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
|
+
var import_node_async_hooks = require("node:async_hooks");
|
|
37
|
+
var import_better_auth = require("better-auth");
|
|
38
|
+
var import_api = require("better-auth/api");
|
|
39
|
+
var import_cookies = require("better-auth/cookies");
|
|
40
|
+
var import_plugins = require("better-auth/plugins");
|
|
41
|
+
var import_expo = require("@better-auth/expo");
|
|
42
|
+
var import_accessTokenRefresh = require("./accessTokenRefresh.cjs");
|
|
43
|
+
var import_accessTokenRefresh2 = require("./accessTokenRefresh.cjs");
|
|
44
|
+
const requestOriginStorage = new import_node_async_hooks.AsyncLocalStorage();
|
|
45
|
+
function deriveRequestOrigin(req) {
|
|
46
|
+
const isDevHost = host => DEV_LAN_HOST_PATTERNS.some(pattern => (0, import_better_auth.matchesHostPattern)(host, pattern));
|
|
47
|
+
const forwardedHost = req.headers.get("x-forwarded-host");
|
|
48
|
+
if (forwardedHost && isDevHost(forwardedHost)) {
|
|
49
|
+
const proto = req.headers.get("x-forwarded-proto") === "https" ? "https" : "http";
|
|
50
|
+
return `${proto}://${forwardedHost}`;
|
|
51
|
+
}
|
|
52
|
+
const originHeader = req.headers.get("origin");
|
|
53
|
+
if (originHeader) {
|
|
54
|
+
try {
|
|
55
|
+
const url = new URL(originHeader);
|
|
56
|
+
if (isDevHost(url.host)) return url.origin;
|
|
57
|
+
} catch {}
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
return new URL(req.url).origin;
|
|
61
|
+
} catch {
|
|
62
|
+
return void 0;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const DEV_LAN_HOST_PATTERNS = ["localhost", "localhost:*", "127.0.0.1", "127.0.0.1:*", "10.*", "192.168.*", "172.*", "*.local", "*.local:*"];
|
|
66
|
+
function createKeycloakSsoPlugin(options) {
|
|
67
|
+
const {
|
|
68
|
+
realm,
|
|
69
|
+
clientId,
|
|
70
|
+
clientSecret,
|
|
71
|
+
issuer,
|
|
72
|
+
baseUrl,
|
|
73
|
+
publicKeycloakBaseFor
|
|
74
|
+
} = options;
|
|
75
|
+
const tokenEndpoint = `${issuer}/protocol/openid-connect/token`;
|
|
76
|
+
const resolveVisitorOrigin = request => requestOriginStorage.getStore() ?? (request ? deriveRequestOrigin(request) : void 0);
|
|
77
|
+
const isRefreshDefinitivelyDead = async refreshToken => {
|
|
78
|
+
try {
|
|
79
|
+
const res = await fetch(tokenEndpoint, {
|
|
80
|
+
method: "POST",
|
|
81
|
+
headers: {
|
|
82
|
+
"content-type": "application/x-www-form-urlencoded"
|
|
83
|
+
},
|
|
84
|
+
body: new URLSearchParams({
|
|
85
|
+
grant_type: "refresh_token",
|
|
86
|
+
refresh_token: refreshToken,
|
|
87
|
+
client_id: clientId,
|
|
88
|
+
client_secret: clientSecret
|
|
89
|
+
}),
|
|
90
|
+
signal: AbortSignal.timeout(5e3)
|
|
91
|
+
});
|
|
92
|
+
if (res.ok) return false;
|
|
93
|
+
if (res.status !== 400 && res.status !== 401) return false;
|
|
94
|
+
const body = await res.json().catch(() => null);
|
|
95
|
+
return body?.error === "invalid_grant" || body?.error === "invalid_token";
|
|
96
|
+
} catch {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
const signOutSso = (0, import_api.createAuthEndpoint)("/sign-out/sso", {
|
|
101
|
+
method: "GET"
|
|
102
|
+
}, async ctx => {
|
|
103
|
+
const visitorOrigin = resolveVisitorOrigin(ctx.request) ?? baseUrl;
|
|
104
|
+
const searchParams = ctx.request ? new URL(ctx.request.url).searchParams : void 0;
|
|
105
|
+
const rawCallback = searchParams?.get("callbackURL") ?? null;
|
|
106
|
+
const jsonMode = searchParams?.get("mode") === "json";
|
|
107
|
+
const answer = (url, redirect) => {
|
|
108
|
+
if (jsonMode) return ctx.json({
|
|
109
|
+
redirect,
|
|
110
|
+
url
|
|
111
|
+
});
|
|
112
|
+
throw ctx.redirect(url);
|
|
113
|
+
};
|
|
114
|
+
const callbackURL = rawCallback || "/";
|
|
115
|
+
const postLogoutRedirect = callbackURL.startsWith("/") ? `${visitorOrigin}${callbackURL}` : callbackURL;
|
|
116
|
+
let idTokenHint;
|
|
117
|
+
const sessionToken = await ctx.getSignedCookie(ctx.context.authCookies.sessionToken.name, ctx.context.secret);
|
|
118
|
+
const session = await (0, import_api.getSessionFromCtx)(ctx).catch(() => null);
|
|
119
|
+
if (session) {
|
|
120
|
+
const accounts = await ctx.context.internalAdapter.findAccounts(session.user.id).catch(() => []);
|
|
121
|
+
idTokenHint = accounts.find(account => account.providerId === "keycloak")?.idToken ?? void 0;
|
|
122
|
+
}
|
|
123
|
+
if (!idTokenHint) {
|
|
124
|
+
const accountCookie = await (0, import_cookies.getAccountCookie)(ctx).catch(() => null);
|
|
125
|
+
if (accountCookie?.providerId === "keycloak" && accountCookie.idToken) {
|
|
126
|
+
idTokenHint = accountCookie.idToken;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (sessionToken) {
|
|
130
|
+
await ctx.context.internalAdapter.deleteSession(sessionToken).catch(error => {
|
|
131
|
+
ctx.context.logger.error("Failed to delete session during SSO sign-out", error);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
(0, import_cookies.deleteSessionCookie)(ctx);
|
|
135
|
+
const keycloakBase = publicKeycloakBaseFor(visitorOrigin);
|
|
136
|
+
if (!keycloakBase || !session && !idTokenHint && !sessionToken) {
|
|
137
|
+
return answer(postLogoutRedirect, false);
|
|
138
|
+
}
|
|
139
|
+
const endSession = new URL(`${keycloakBase}/realms/${realm}/protocol/openid-connect/logout`);
|
|
140
|
+
endSession.searchParams.set("post_logout_redirect_uri", postLogoutRedirect);
|
|
141
|
+
endSession.searchParams.set("client_id", clientId);
|
|
142
|
+
if (idTokenHint) endSession.searchParams.set("id_token_hint", idTokenHint);
|
|
143
|
+
return answer(endSession.toString(), true);
|
|
144
|
+
});
|
|
145
|
+
return {
|
|
146
|
+
id: "keycloak-sso",
|
|
147
|
+
endpoints: {
|
|
148
|
+
signOutSso
|
|
149
|
+
},
|
|
150
|
+
hooks: {
|
|
151
|
+
after: [{
|
|
152
|
+
matcher: ctx => ctx.path === "/get-access-token",
|
|
153
|
+
handler: (0, import_api.createAuthMiddleware)(async ctx => {
|
|
154
|
+
const returned = ctx.context.returned;
|
|
155
|
+
if (!(0, import_api.isAPIError)(returned)) return;
|
|
156
|
+
const body = returned.body;
|
|
157
|
+
if (body?.code !== import_accessTokenRefresh.FAILED_TO_GET_ACCESS_TOKEN) return;
|
|
158
|
+
const providerId = ctx.body?.providerId;
|
|
159
|
+
if (providerId && providerId !== "keycloak") return;
|
|
160
|
+
const session = await (0, import_api.getSessionFromCtx)(ctx).catch(() => null);
|
|
161
|
+
if (!session) return;
|
|
162
|
+
const accounts = await ctx.context.internalAdapter.findAccounts(session.user.id).catch(() => []);
|
|
163
|
+
let refreshToken = accounts.find(account => account.providerId === "keycloak")?.refreshToken;
|
|
164
|
+
if (!refreshToken) {
|
|
165
|
+
const accountCookie = await (0, import_cookies.getAccountCookie)(ctx).catch(() => null);
|
|
166
|
+
if (accountCookie?.providerId === "keycloak") {
|
|
167
|
+
refreshToken = accountCookie.refreshToken;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const definitive = refreshToken ? await isRefreshDefinitivelyDead(refreshToken) : true;
|
|
171
|
+
if (!definitive) {
|
|
172
|
+
return new import_api.APIError("INTERNAL_SERVER_ERROR", {
|
|
173
|
+
message: "Keycloak token refresh temporarily unavailable",
|
|
174
|
+
code: import_accessTokenRefresh.TOKEN_REFRESH_UNAVAILABLE
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
ctx.context.logger.warn("Keycloak refresh token is dead (invalid_grant); revoking the stale Better Auth session");
|
|
178
|
+
const sessionToken = await ctx.getSignedCookie(ctx.context.authCookies.sessionToken.name, ctx.context.secret);
|
|
179
|
+
if (sessionToken) {
|
|
180
|
+
await ctx.context.internalAdapter.deleteSession(sessionToken).catch(error => {
|
|
181
|
+
ctx.context.logger.error("Failed to delete stale session", error);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
(0, import_cookies.deleteSessionCookie)(ctx);
|
|
185
|
+
const headers = new Headers();
|
|
186
|
+
const accumulated = ctx.responseHeaders;
|
|
187
|
+
accumulated?.getSetCookie().forEach(cookie => {
|
|
188
|
+
headers.append("set-cookie", cookie);
|
|
189
|
+
});
|
|
190
|
+
return new import_api.APIError("BAD_REQUEST", {
|
|
191
|
+
message: body?.message || "Failed to get a valid access token",
|
|
192
|
+
code: import_accessTokenRefresh.FAILED_TO_GET_ACCESS_TOKEN
|
|
193
|
+
}, headers);
|
|
194
|
+
})
|
|
195
|
+
}]
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function createAuth(options = {}) {
|
|
200
|
+
const baseUrl = options.baseUrl || process.env.BASE_URL || `http://localhost:${process.env.ONE_PORT || "3000"}`;
|
|
201
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
202
|
+
const keycloakBaseUrl = options.keycloak?.baseUrl || process.env.KEYCLOAK_BACKCHANNEL_URL || `${baseUrl}/auth`;
|
|
203
|
+
const keycloakRealm = options.keycloak?.realm || process.env.KEYCLOAK_REALM || "master";
|
|
204
|
+
const issuer = `${keycloakBaseUrl}/realms/${keycloakRealm}`;
|
|
205
|
+
const keycloakClientId = options.keycloak?.clientId || process.env.KEYCLOAK_CLIENT_ID || "";
|
|
206
|
+
const keycloakClientSecret = options.keycloak?.clientSecret || process.env.KEYCLOAK_CLIENT_SECRET || "";
|
|
207
|
+
const expoPlugin = options.enableExpo !== false ? (0, import_expo.expo)() : void 0;
|
|
208
|
+
const basePath = options.basePath || "/api/auth";
|
|
209
|
+
const keycloakProviderConfig = {
|
|
210
|
+
...(0, import_plugins.keycloak)({
|
|
211
|
+
clientId: keycloakClientId,
|
|
212
|
+
clientSecret: keycloakClientSecret,
|
|
213
|
+
issuer
|
|
214
|
+
}),
|
|
215
|
+
// Backchannel token/userinfo: `/get-access-token` refresh keeps these
|
|
216
|
+
// when discovery fails (Keycloak restart), so we don't depend on the
|
|
217
|
+
// well-known document coming up in the same instant as the token
|
|
218
|
+
// endpoint. Browser-facing authorize/issuer stay on the public /auth
|
|
219
|
+
// proxy (getters below).
|
|
220
|
+
tokenUrl: `${issuer}/protocol/openid-connect/token`,
|
|
221
|
+
userInfoUrl: `${issuer}/protocol/openid-connect/userinfo`,
|
|
222
|
+
// Wallet (SIWE-style) users authenticate by signature and have NO email —
|
|
223
|
+
// Keycloak issues them a username = wallet address and no email claim.
|
|
224
|
+
// better-auth's genericOAuth callback hard-rejects a user with no email
|
|
225
|
+
// ("email_is_missing"), so synthesize a stable, unique placeholder from the
|
|
226
|
+
// wallet address / subject. `.wallet` is a non-routable placeholder domain;
|
|
227
|
+
// the address stays the stable identity.
|
|
228
|
+
mapProfileToUser: profile => {
|
|
229
|
+
const handle = profile.preferred_username || profile.sub || profile.id || profile.name;
|
|
230
|
+
const email = profile.email || (handle ? `${handle}@wallet` : void 0);
|
|
231
|
+
return {
|
|
232
|
+
...profile,
|
|
233
|
+
email,
|
|
234
|
+
emailVerified: profile.email_verified ?? true,
|
|
235
|
+
name: profile.name || handle
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
const keycloakPublicPath = (() => {
|
|
240
|
+
try {
|
|
241
|
+
const path = new URL(keycloakBaseUrl).pathname.replace(/\/+$/, "");
|
|
242
|
+
return path && path !== "/" ? path : void 0;
|
|
243
|
+
} catch {
|
|
244
|
+
return void 0;
|
|
245
|
+
}
|
|
246
|
+
})();
|
|
247
|
+
const publicKeycloakBaseFor = requestOrigin => {
|
|
248
|
+
if (!keycloakPublicPath) return keycloakBaseUrl;
|
|
249
|
+
try {
|
|
250
|
+
const url = new URL(baseUrl);
|
|
251
|
+
if (!isProduction && requestOrigin) {
|
|
252
|
+
url.hostname = new URL(requestOrigin).hostname;
|
|
253
|
+
}
|
|
254
|
+
return `${url.origin}${keycloakPublicPath}`;
|
|
255
|
+
} catch {
|
|
256
|
+
return void 0;
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
if (!isProduction) {
|
|
260
|
+
Object.defineProperty(keycloakProviderConfig, "redirectURI", {
|
|
261
|
+
enumerable: true,
|
|
262
|
+
get() {
|
|
263
|
+
const origin = requestOriginStorage.getStore();
|
|
264
|
+
return origin ? `${origin}${basePath}/oauth2/callback/keycloak` : void 0;
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
const keycloakPublicBase = () => {
|
|
268
|
+
const origin = requestOriginStorage.getStore();
|
|
269
|
+
if (!origin || !keycloakPublicPath) return void 0;
|
|
270
|
+
return publicKeycloakBaseFor(origin);
|
|
271
|
+
};
|
|
272
|
+
if (keycloakPublicPath) {
|
|
273
|
+
Object.defineProperty(keycloakProviderConfig, "authorizationUrl", {
|
|
274
|
+
enumerable: true,
|
|
275
|
+
get() {
|
|
276
|
+
const base = keycloakPublicBase();
|
|
277
|
+
return base ? `${base}/realms/${keycloakRealm}/protocol/openid-connect/auth` : void 0;
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
Object.defineProperty(keycloakProviderConfig, "issuer", {
|
|
281
|
+
enumerable: true,
|
|
282
|
+
get() {
|
|
283
|
+
const base = keycloakPublicBase();
|
|
284
|
+
return base ? `${base}/realms/${keycloakRealm}` : void 0;
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const oauthPlugin = (0, import_plugins.genericOAuth)({
|
|
290
|
+
config: [keycloakProviderConfig]
|
|
291
|
+
});
|
|
292
|
+
const keycloakSsoPlugin = createKeycloakSsoPlugin({
|
|
293
|
+
realm: keycloakRealm,
|
|
294
|
+
clientId: keycloakClientId,
|
|
295
|
+
clientSecret: keycloakClientSecret,
|
|
296
|
+
issuer,
|
|
297
|
+
baseUrl,
|
|
298
|
+
publicKeycloakBaseFor
|
|
299
|
+
});
|
|
300
|
+
const plugins = [...(expoPlugin ? [expoPlugin] : []), oauthPlugin, keycloakSsoPlugin, ...(options.plugins ?? [])];
|
|
301
|
+
const database = options.database ?? (process.env.DATABASE_URL || void 0);
|
|
302
|
+
return (0, import_better_auth.betterAuth)({
|
|
303
|
+
basePath,
|
|
304
|
+
// Static on purpose: better-auth's dynamic `baseURL` config (allowedHosts)
|
|
305
|
+
// is not honored by the genericOAuth plugin — it pins redirect URIs at
|
|
306
|
+
// init time, which turned them relative and bounced callbacks to the
|
|
307
|
+
// Keycloak host. Dev multi-host support comes from the per-request
|
|
308
|
+
// redirectURI getter above + the LAN trustedOrigins below instead.
|
|
309
|
+
baseURL: baseUrl,
|
|
310
|
+
...(database ? {
|
|
311
|
+
database
|
|
312
|
+
} : {}),
|
|
313
|
+
secret: options.secret || process.env.SECRET || "",
|
|
314
|
+
trustedOrigins: options.trustedOrigins || [baseUrl, keycloakBaseUrl,
|
|
315
|
+
// In dev, ONE_PORT may differ from BASE_URL; ensure the dev server origin is trusted.
|
|
316
|
+
...(process.env.ONE_PORT && !baseUrl.includes(`:${process.env.ONE_PORT}`) ? [`http://localhost:${process.env.ONE_PORT}`] : []), "multiplatform-one://",
|
|
317
|
+
// Expo Go (dev) receives OAuth returns on the exp:// scheme — the app
|
|
318
|
+
// derives its callbackURL via Linking.createURL, which yields
|
|
319
|
+
// exp://<host>:<port>/--/ there. Never trusted in production builds.
|
|
320
|
+
// Dev also trusts private-network origins (see DEV_LAN_HOST_PATTERNS)
|
|
321
|
+
// so sign-in from a phone / the machine's LAN IP is not rejected.
|
|
322
|
+
...(isProduction ? [] : ["exp://", ...DEV_LAN_HOST_PATTERNS.map(host => `http://${host}`)])],
|
|
323
|
+
session: {
|
|
324
|
+
cookieCache: {
|
|
325
|
+
enabled: true,
|
|
326
|
+
maxAge: options.sessionMaxAge ?? 7 * 24 * 60 * 60,
|
|
327
|
+
strategy: "jwe",
|
|
328
|
+
refreshCache: true
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
account: {
|
|
332
|
+
storeStateStrategy: "cookie",
|
|
333
|
+
storeAccountCookie: true
|
|
334
|
+
},
|
|
335
|
+
plugins
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
function createAuthRouteHandler(auth) {
|
|
339
|
+
const handler = req => {
|
|
340
|
+
const origin = deriveRequestOrigin(req);
|
|
341
|
+
return origin ? requestOriginStorage.run(origin, () => auth.handler(req)) : auth.handler(req);
|
|
342
|
+
};
|
|
343
|
+
return {
|
|
344
|
+
GET: handler,
|
|
345
|
+
POST: handler
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
function createSessionHelpers(auth) {
|
|
349
|
+
async function getSession(req) {
|
|
350
|
+
return auth.api.getSession({
|
|
351
|
+
headers: req.headers
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
async function verifyAuth(req) {
|
|
355
|
+
const session = await auth.api.getSession({
|
|
356
|
+
headers: req.headers
|
|
357
|
+
});
|
|
358
|
+
if (!session) {
|
|
359
|
+
throw new Response("Unauthorized", {
|
|
360
|
+
status: 401
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
return session;
|
|
364
|
+
}
|
|
365
|
+
return {
|
|
366
|
+
verifyAuth,
|
|
367
|
+
getSession
|
|
368
|
+
};
|
|
369
|
+
}
|