aui-auth 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/accounts.d.ts +2 -2
- package/dist/accounts.js +1 -1
- package/dist/cache-DuVjR2sZ.js +1 -0
- package/dist/codec-BcgaGRoP.js +1 -0
- package/dist/database/index.d.ts +2 -0
- package/dist/database/index.js +1 -0
- package/dist/{pg.d.ts → database/pg.d.ts} +3 -6
- package/dist/{pg.js → database/pg.js} +1 -1
- package/dist/{index-CICWi97l.d.ts → index-CiWgJQWW.d.ts} +25 -11
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/next.d.ts +3 -3
- package/dist/next.js +1 -1
- package/dist/{types-CRiqvt6N.d.ts → types-C79_29ZY.d.ts} +22 -3
- package/package.json +11 -7
- package/dist/cookies-D3lpM5ER.js +0 -1
- package/dist/oidc-BIfcHoyS.js +0 -1
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
# aui-auth
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Server-side sessions for web apps that sign in through assistant-ui accounts: OpenID Connect with PKCE, tokens kept in the app's own database, single-flight refresh, and an encrypted cache cookie. Internal to assistant-ui; the manual is `docs/first-party-auth.md` and the design is `packages/aui-auth/ARCHITECTURE.md` in the assistant-internal repository.
|
|
4
|
+
|
|
5
|
+
Entry points: `aui-auth`, `aui-auth/accounts`, `aui-auth/next`, `aui-auth/database`, `aui-auth/database/pg`.
|
package/dist/accounts.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
//#region src/accounts.d.ts
|
|
1
|
+
import { m as SignInInput, p as RevalidateInput } from "./types-C79_29ZY.js";
|
|
2
|
+
//#region src/accounts/index.d.ts
|
|
3
3
|
type AccountsOrganization = {
|
|
4
4
|
id: string;
|
|
5
5
|
name: string;
|
package/dist/accounts.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{a as e,m as t}from"./cache-DuVjR2sZ.js";async function n(n,r){let i=await(n.fetch??globalThis.fetch.bind(globalThis))(e(n.issuer,`/api/oidc/organizations`),{headers:{Authorization:`Bearer ${r}`},cache:`no-store`});if(!i.ok)throw new t(`Failed to load organizations: ${i.status}`,i.status);return await i.json()}function r(e,t){if(t){let n=e.find(e=>e.slug===t);if(n)return n}return e[0]??null}function i(e){let[,t]=new URL(e,`http://localhost`).pathname.split(`/`);return t&&t!==`org`?t:null}function a(e){let a=e.preferredSlug??i;async function o(t){return{activeOrganization:r(await n(e,t.accessToken),a(t.redirectPath))}}async function s(i){let a;try{a=await n(e,i.accessToken)}catch(e){if(e instanceof t&&e.status>=400&&e.status<500)return null;throw e}let o=i.session.data.activeOrganization;if(!o)return{activeOrganization:r(a)};let s=a.find(e=>e.id===o.id)??null;return s?{activeOrganization:s}:null}return{onSignIn:o,onRevalidate:s}}export{n as fetchOrganizations,a as organizationHooks,i as preferredOrganizationSlug,r as selectOrganization};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./codec-BcgaGRoP.js";function t(e){if(!e)return;let t=e.split(`,`);return t[t.length-1].trim()||void 0}function n(e){let n=new URL(e.url);return`${t(e.headers.get(`x-forwarded-proto`))||n.protocol.replace(`:`,``)}://${t(e.headers.get(`x-forwarded-host`))||e.headers.get(`host`)||n.host}`}function r(e){return new URL(e).protocol===`https:`}function i(e,t){return t?`__Secure-${e}`:e}function a(e){let t=new Map;if(!e)return t;for(let n of e.split(`;`)){let e=n.indexOf(`=`);if(e===-1)continue;let r=n.slice(0,e).trim();!r||t.has(r)||t.set(r,n.slice(e+1).trim())}return t}function o(e,t){let n=a(e.headers.get(`cookie`));return n.get(i(t,!0))||n.get(i(t,!1))||null}function s(e,t,n,r){let i=[`${e}=${t}`,`Path=/`,`HttpOnly`,`SameSite=Lax`,`Max-Age=${r}`];return n&&i.push(`Secure`),i.join(`; `)}function c(e,t,n,a,o){let c=r(a);e.append(`set-cookie`,s(i(t,c),n,c,Math.floor(o/1e3)))}function l(e,t,n){let a=r(n);for(let n of[a,!a])e.append(`set-cookie`,s(i(t,n),``,n,0))}function u(e,t=307){return new Response(null,{status:t,headers:{location:e.toString()}})}function d(e,t){return`${e}_flow_${t}`}function f(e){return btoa(JSON.stringify(e)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/g,``)}function p(e){if(!e)return null;try{let t=e.replace(/-/g,`+`).replace(/_/g,`/`),n=JSON.parse(atob(t));return typeof n.verifier==`string`?{verifier:n.verifier,redirectPath:typeof n.redirectPath==`string`?n.redirectPath:`/`,silent:n.silent===!0}:null}catch{return null}}function m(e,t){if(!e)return`/`;let n;try{n=new URL(e,t)}catch{return`/`}return n.origin===t?`${n.pathname}${n.search}${n.hash}`:`/`}const h={login:`/api/auth/login`,callback:`/api/auth/callback`,logout:`/api/auth/logout`,logoutComplete:`/api/auth/logout-complete`,error:`/auth/error`},g={absoluteMaxAgeMs:2592e6,idleMaxAgeMs:6048e5,revalidateIntervalMs:12e4,refreshBeforeExpiryMs:3e5,flowMaxAgeMs:6e5,refreshLeaseMs:2e4,leaseWaitMs:5e3};function _(e){return{...e,scope:e.scope??`openid profile email offline_access`,paths:{...h,...e.paths},lifetimes:{...g,...e.lifetimes},fetch:e.fetch??globalThis.fetch.bind(globalThis),now:e.now??Date.now,cache:e.cache?{codec:N(e.cache.secret),maxAgeMs:e.cache.maxAgeMs??6e4}:null,audience:e.audience===!1?null:e.audience??new URL(`/api/auth`,e.issuer).toString()}}var v=class extends Error{status;constructor(e,t){super(e),this.name=`AccountsRequestError`,this.status=t}},y=class extends v{code;description;constructor(e,t,n){super(`Token request failed: ${e} ${t} ${n}`,e),this.name=`OAuthTokenError`,this.code=t,this.description=n}};function b(e){let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/g,``)}function x(e){return b(crypto.getRandomValues(new Uint8Array(e)))}async function S(e){let t=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(e));return b(new Uint8Array(t))}function C(e,t){return new URL(t,e).toString()}async function w(e,t){let n=x(24),r=x(32),i=new URL(C(e.issuer,`/api/auth/oauth2/authorize`));return i.searchParams.set(`client_id`,e.clientId),i.searchParams.set(`redirect_uri`,new URL(e.paths.callback,t.origin).toString()),i.searchParams.set(`response_type`,`code`),i.searchParams.set(`scope`,e.scope),i.searchParams.set(`state`,n),i.searchParams.set(`code_challenge`,await S(r)),i.searchParams.set(`code_challenge_method`,`S256`),t.silent&&i.searchParams.set(`prompt`,`none`),{url:i.toString(),state:n,verifier:r}}function T(e,t){let n=new URL(C(e.issuer,`/api/auth/oauth2/end-session`));return n.searchParams.set(`id_token_hint`,t.idToken),n.searchParams.set(`client_id`,e.clientId),n.searchParams.set(`post_logout_redirect_uri`,new URL(e.paths.logoutComplete,t.origin).toString()),n.toString()}async function E(e,t,n,r=!0){let i=new URLSearchParams({client_id:e.clientId,...t});e.clientSecret&&i.set(`client_secret`,e.clientSecret),e.audience&&r&&i.set(`resource`,e.audience);let a=n===void 0?void 0:n-Date.now();if(a!==void 0&&a<=0)throw new v(`Token request deadline passed`,0);let o=await e.fetch(C(e.issuer,`/api/auth/oauth2/token`),{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:i,cache:`no-store`,...a?{signal:AbortSignal.timeout(a)}:{}});if(!o.ok){let i=await o.text().catch(()=>``),a=`unknown_error`,s=i;try{let e=JSON.parse(i);a=e.error??a,s=e.error_description??s}catch{}if(r&&e.audience&&a===`invalid_request`&&/resource/i.test(s))return E(e,t,n,!1);throw new y(o.status,a,s)}return await o.json()}function D(e,t){return E(e,{grant_type:`authorization_code`,code:t.code,code_verifier:t.verifier,redirect_uri:t.redirectUri})}function O(e,t,n){return E(e,{grant_type:`refresh_token`,refresh_token:t},n===void 0?void 0:Date.now()+n)}async function k(e,t){let n=await(e.fetch??globalThis.fetch.bind(globalThis))(C(e.issuer,`/api/auth/oauth2/userinfo`),{headers:{Authorization:`Bearer ${t}`},cache:`no-store`});if(!n.ok)throw new v(`Failed to load user info: ${n.status}`,n.status);let r=await n.json();return{id:r.sub,email:r.email??``,name:r.name??r.email??r.sub,image:r.picture??null}}function A(e,t,n){return{accessToken:e.access_token,refreshToken:e.refresh_token??t?.refreshToken??null,idToken:e.id_token??t?.idToken??null,accessTokenExpiresAt:typeof e.expires_at==`number`?e.expires_at*1e3:n+(e.expires_in??3600)*1e3}}function j(e){return`${e}_cache`}function M(e){let t=``;for(let n of e)t+=n.toString(16).padStart(2,`0`);return t}function N(t){let n=null;return()=>n??=crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(t)).then(t=>e(M(new Uint8Array(t))))}function P(e,t,n){if(!e.cache)return 0;let{lifetimes:r}=e;return Math.min(e.cache.maxAgeMs,t.lastValidatedAt+r.revalidateIntervalMs-n,t.tokens.accessTokenExpiresAt-r.refreshBeforeExpiryMs-n,t.createdAt+r.absoluteMaxAgeMs-n,t.lastValidatedAt+r.idleMaxAgeMs-n)}async function F(e,t,n){if(!e.cache)return null;let r=P(e,t,n);if(r<1e3)return null;let i={v:1,id:t.id,u:t.user,d:t.data,at:t.tokens.accessToken,ate:t.tokens.accessTokenExpiresAt,ca:t.createdAt,lv:t.lastValidatedAt,exp:n+r};return{value:await(await e.cache.codec()).encrypt(JSON.stringify(i)),maxAgeMs:r}}async function I(e,t,n,r){if(!e.cache||!t||!n)return null;let i;try{let n=await e.cache.codec();i=JSON.parse(await n.decrypt(t))}catch{return null}return i.v!==1||typeof i.exp!=`number`||i.exp<=r||i.id!==await S(n)?null:{id:i.id,user:i.u,tokens:{accessToken:i.at,refreshToken:null,idToken:null,accessTokenExpiresAt:i.ate},data:i.d,createdAt:i.ca,lastValidatedAt:i.lv,refreshLeaseUntil:null}}async function L(e,t,n,a){let o=await F(e,t,a);if(!o)return null;let c=r(n);return s(i(j(e.cookieName),c),o.value,c,Math.floor(o.maxAgeMs/1e3))}function R(e,t){if(!e.cache)return[];let n=r(t),a=j(e.cookieName);return[n,!n].map(e=>s(i(a,e),``,e,0))}export{u as C,c as E,o as S,m as T,l as _,C as a,f as b,D as c,O as d,S as f,_ as g,y as h,I as i,k as l,v as m,j as n,w as o,A as p,L as r,T as s,R as t,x as u,i as v,n as w,d as x,p as y};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e){let t=new Uint8Array(e.length/2);for(let n=0;n<e.length;n+=2)t[n/2]=Number.parseInt(e.slice(n,n+2),16);return t}function t(e){let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/g,``)}function n(e){let t=e.replace(/-/g,`+`).replace(/_/g,`/`),n=t+`=`.repeat((4-t.length%4)%4),r;try{r=atob(n)}catch{throw Error(`Malformed encrypted value`)}let i=new Uint8Array(r.length);for(let e=0;e<r.length;e++)i[e]=r.charCodeAt(e);return i}function r(r){if(!/^[0-9a-fA-F]{64}$/.test(r))throw Error(`AES-GCM codec key must be 64 hex characters (32 bytes)`);let i=e(r),a=null,o=()=>a??=crypto.subtle.importKey(`raw`,i,{name:`AES-GCM`},!1,[`encrypt`,`decrypt`]);return{async encrypt(e){let n=crypto.getRandomValues(new Uint8Array(12)),r=new Uint8Array(await crypto.subtle.encrypt({name:`AES-GCM`,iv:n},await o(),new TextEncoder().encode(e))),i=new Uint8Array(12+r.length);return i.set(n),i.set(r,12),t(i)},async decrypt(e){let t=n(e);if(t.length<28)throw Error(`Malformed encrypted value`);let r=await crypto.subtle.decrypt({name:`AES-GCM`,iv:t.subarray(0,12)},await o(),t.subarray(12));return new TextDecoder().decode(r)}}}export{r as t};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { c as AccountsSessionStore, g as createAesGcmCodec, h as SessionCodec, l as AccountsTokens, o as AccountsSession, s as AccountsSessionPatch, u as AccountsUser } from "../types-C79_29ZY.js";
|
|
2
|
+
export { type AccountsSession, type AccountsSessionPatch, type AccountsSessionStore, type AccountsTokens, type AccountsUser, type SessionCodec, createAesGcmCodec };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"../codec-BcgaGRoP.js";export{e as createAesGcmCodec};
|
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
//#region src/pg.d.ts
|
|
1
|
+
import { c as AccountsSessionStore, h as SessionCodec } from "../types-C79_29ZY.js";
|
|
2
|
+
//#region src/database/pg.d.ts
|
|
3
3
|
type PgQuery = (text: string, values?: unknown[]) => Promise<{
|
|
4
4
|
rows: Record<string, unknown>[];
|
|
5
5
|
}>;
|
|
6
6
|
type PgSessionStoreOptions = {
|
|
7
7
|
query: PgQuery;
|
|
8
8
|
table?: string;
|
|
9
|
-
codec?:
|
|
10
|
-
encrypt(value: string): Promise<string>;
|
|
11
|
-
decrypt(value: string): Promise<string>;
|
|
12
|
-
};
|
|
9
|
+
codec?: SessionCodec;
|
|
13
10
|
};
|
|
14
11
|
declare const PG_SESSION_TABLE_SQL = "CREATE TABLE \"accounts_sessions\" (\n \"id\" text PRIMARY KEY,\n \"user_id\" text NOT NULL,\n \"user\" jsonb NOT NULL,\n \"access_token\" text NOT NULL,\n \"refresh_token\" text,\n \"id_token\" text,\n \"access_token_expires_at\" timestamp with time zone NOT NULL,\n \"data\" jsonb NOT NULL,\n \"created_at\" timestamp with time zone NOT NULL,\n \"last_validated_at\" timestamp with time zone NOT NULL,\n \"refresh_lease_until\" timestamp with time zone\n);\nCREATE INDEX \"accounts_sessions_user_id_idx\" ON \"accounts_sessions\" (\"user_id\");";
|
|
15
12
|
declare function createPgSessionStore<Data>(options: PgSessionStoreOptions): AccountsSessionStore<Data>;
|
|
@@ -11,4 +11,4 @@ const e=`CREATE TABLE "accounts_sessions" (
|
|
|
11
11
|
"last_validated_at" timestamp with time zone NOT NULL,
|
|
12
12
|
"refresh_lease_until" timestamp with time zone
|
|
13
13
|
);
|
|
14
|
-
CREATE INDEX "accounts_sessions_user_id_idx" ON "accounts_sessions" ("user_id");`,t={encrypt:async e=>e,decrypt:async e=>e};function n(e){if(e instanceof Date)return e.getTime();if(typeof e==`string`)return new Date(e).getTime();if(typeof e==`number`)return e;throw Error(`Unexpected timestamp value in accounts session row`)}function r(e){return new Date(e)}function i(e){let i=e.table??`accounts_sessions`;if(!/^[a-z_][a-z0-9_]*$/.test(i))throw Error(`Invalid accounts session table name: ${i}`);let a=`"${i}"`,o=e.codec??t;async function s(e){return{accessToken:await o.encrypt(e.accessToken),refreshToken:e.refreshToken?await o.encrypt(e.refreshToken):null,idToken:e.idToken?await o.encrypt(e.idToken):null}}async function c(e){return{id:e.id,user:e.user,tokens:{accessToken:await o.decrypt(e.access_token),refreshToken:e.refresh_token?await o.decrypt(e.refresh_token):null,idToken:e.id_token?await o.decrypt(e.id_token):null,accessTokenExpiresAt:n(e.access_token_expires_at)},data:e.data,createdAt:n(e.created_at),lastValidatedAt:n(e.last_validated_at),refreshLeaseUntil:e.refresh_lease_until===null||e.refresh_lease_until===void 0?null:n(e.refresh_lease_until)}}return{async create(t){let n=await s(t.tokens);await e.query(`INSERT INTO ${a} ("id", "user_id", "user", "access_token", "refresh_token", "id_token", "access_token_expires_at", "data", "created_at", "last_validated_at", "refresh_lease_until") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, NULL)`,[t.id,t.user.id,
|
|
14
|
+
CREATE INDEX "accounts_sessions_user_id_idx" ON "accounts_sessions" ("user_id");`,t={encrypt:async e=>e,decrypt:async e=>e};function n(e){if(e instanceof Date)return e.getTime();if(typeof e==`string`)return new Date(e).getTime();if(typeof e==`number`)return e;throw Error(`Unexpected timestamp value in accounts session row`)}function r(e){return new Date(e)}function i(e){let i=e.table??`accounts_sessions`;if(!/^[a-z_][a-z0-9_]*$/.test(i))throw Error(`Invalid accounts session table name: ${i}`);let a=`"${i}"`,o=e.codec??t;async function s(e){return{accessToken:await o.encrypt(e.accessToken),refreshToken:e.refreshToken?await o.encrypt(e.refreshToken):null,idToken:e.idToken?await o.encrypt(e.idToken):null}}async function c(e){return{id:e.id,user:e.user,tokens:{accessToken:await o.decrypt(e.access_token),refreshToken:e.refresh_token?await o.decrypt(e.refresh_token):null,idToken:e.id_token?await o.decrypt(e.id_token):null,accessTokenExpiresAt:n(e.access_token_expires_at)},data:e.data,createdAt:n(e.created_at),lastValidatedAt:n(e.last_validated_at),refreshLeaseUntil:e.refresh_lease_until===null||e.refresh_lease_until===void 0?null:n(e.refresh_lease_until)}}return{async create(t){let n=await s(t.tokens);await e.query(`INSERT INTO ${a} ("id", "user_id", "user", "access_token", "refresh_token", "id_token", "access_token_expires_at", "data", "created_at", "last_validated_at", "refresh_lease_until") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, NULL)`,[t.id,t.user.id,t.user,n.accessToken,n.refreshToken,n.idToken,r(t.tokens.accessTokenExpiresAt),t.data,r(t.createdAt),r(t.lastValidatedAt)])},async read(t){let{rows:n}=await e.query(`SELECT * FROM ${a} WHERE "id" = $1`,[t]);return n[0]?c(n[0]):null},async update(t,n,i){let o=[],l=[t],u=(e,t)=>{l.push(t),o.push(`"${e}" = $${l.length}`)};if(n.user!==void 0&&(u(`user_id`,n.user.id),u(`user`,n.user)),n.tokens!==void 0){let e=await s(n.tokens);u(`access_token`,e.accessToken),u(`refresh_token`,e.refreshToken),u(`id_token`,e.idToken),u(`access_token_expires_at`,r(n.tokens.accessTokenExpiresAt))}if(n.data!==void 0&&u(`data`,n.data),n.lastValidatedAt!==void 0&&u(`last_validated_at`,r(n.lastValidatedAt)),n.refreshLeaseUntil!==void 0&&u(`refresh_lease_until`,n.refreshLeaseUntil===null?null:r(n.refreshLeaseUntil)),o.length===0)return this.read(t);let d=`"id" = $1`;i!==void 0&&(l.push(r(i)),d+=` AND "refresh_lease_until" = $${l.length}`);let{rows:f}=await e.query(`UPDATE ${a} SET ${o.join(`, `)} WHERE ${d} RETURNING *`,l);return f[0]?c(f[0]):null},async claimRefreshLease(t,n,i){let{rows:o}=await e.query(`UPDATE ${a} SET "refresh_lease_until" = $2 WHERE "id" = $1 AND ("refresh_lease_until" IS NULL OR "refresh_lease_until" <= $3) RETURNING *`,[t,r(n),r(i)]);return o[0]?c(o[0]):null},async delete(t,n){if(n===void 0){await e.query(`DELETE FROM ${a} WHERE "id" = $1`,[t]);return}await e.query(`DELETE FROM ${a} WHERE "id" = $1 AND "refresh_lease_until" = $2`,[t,r(n)])}}}export{e as PG_SESSION_TABLE_SQL,i as createPgSessionStore};
|
|
@@ -1,5 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
//#region src/
|
|
1
|
+
import { c as AccountsSessionStore, f as ResolvedAccountsAuthConfig, l as AccountsTokens, o as AccountsSession, t as AccountsAuthConfig, u as AccountsUser } from "./types-C79_29ZY.js";
|
|
2
|
+
//#region src/core/cookies.d.ts
|
|
3
|
+
declare function requestOrigin(request: Request): string;
|
|
4
|
+
declare function sanitizeRedirectPath(rawRedirect: string | null | undefined, origin: string): string;
|
|
5
|
+
//#endregion
|
|
6
|
+
//#region src/core/oidc.d.ts
|
|
7
|
+
declare function accountsEndpoint(issuer: string, path: string): string;
|
|
8
|
+
declare function fetchUserInfo(options: {
|
|
9
|
+
issuer: string;
|
|
10
|
+
fetch?: typeof fetch;
|
|
11
|
+
}, accessToken: string): Promise<AccountsUser>;
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/core/cache.d.ts
|
|
14
|
+
declare function cacheCookieBase(sessionCookie: string): string;
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/core/guard.d.ts
|
|
3
17
|
type GuardOptions = {
|
|
4
18
|
publicPaths?: string[];
|
|
5
19
|
apiPaths?: string[];
|
|
@@ -8,24 +22,22 @@ type GuardOptions = {
|
|
|
8
22
|
type GuardResult<Data> = {
|
|
9
23
|
kind: "ok";
|
|
10
24
|
session: AccountsSession<Data> | null;
|
|
25
|
+
cookies?: string[];
|
|
11
26
|
} | {
|
|
12
27
|
kind: "response";
|
|
13
28
|
response: Response;
|
|
14
29
|
};
|
|
15
30
|
//#endregion
|
|
16
|
-
//#region src/
|
|
17
|
-
declare function requestOrigin(request: Request): string;
|
|
18
|
-
declare function sanitizeRedirectPath(rawRedirect: string | null | undefined, origin: string): string;
|
|
19
|
-
//#endregion
|
|
20
|
-
//#region src/oidc.d.ts
|
|
21
|
-
declare function accountsEndpoint(issuer: string, path: string): string;
|
|
22
|
-
//#endregion
|
|
23
|
-
//#region src/store/memory.d.ts
|
|
31
|
+
//#region src/core/store/memory.d.ts
|
|
24
32
|
declare function createMemorySessionStore<Data>(): AccountsSessionStore<Data> & {
|
|
25
33
|
rows: Map<string, AccountsSession<Data>>;
|
|
26
34
|
};
|
|
27
35
|
//#endregion
|
|
28
36
|
//#region src/index.d.ts
|
|
37
|
+
type SessionCookies = {
|
|
38
|
+
session: string | null;
|
|
39
|
+
cache: string | null;
|
|
40
|
+
};
|
|
29
41
|
declare function createAccountsAuth<Data>(input: AccountsAuthConfig<Data>): {
|
|
30
42
|
config: ResolvedAccountsAuthConfig<Data>;
|
|
31
43
|
sessions: {
|
|
@@ -49,11 +61,13 @@ declare function createAccountsAuth<Data>(input: AccountsAuthConfig<Data>): {
|
|
|
49
61
|
};
|
|
50
62
|
guard: (request: Request, options?: GuardOptions) => Promise<GuardResult<Data>>;
|
|
51
63
|
sessionFromCookie: (cookieValue: string | null) => Promise<AccountsSession<Data> | null>;
|
|
64
|
+
sessionFromCookies: (cookies: SessionCookies) => Promise<AccountsSession<Data> | null>;
|
|
52
65
|
sessionFromRequest: (request: Request) => Promise<AccountsSession<Data> | null>;
|
|
53
66
|
accessTokenFromCookie: (cookieValue: string | null) => Promise<string | null>;
|
|
67
|
+
accessTokenFromCookies: (cookies: SessionCookies) => Promise<string | null>;
|
|
54
68
|
accessTokenFromRequest: (request: Request) => Promise<string | null>;
|
|
55
69
|
updateSessionData: (cookieValue: string | null, update: (data: Data) => Data) => Promise<AccountsSession<Data> | null>;
|
|
56
70
|
};
|
|
57
71
|
type AccountsAuth<Data> = ReturnType<typeof createAccountsAuth<Data>>;
|
|
58
72
|
//#endregion
|
|
59
|
-
export {
|
|
73
|
+
export { GuardOptions as a, accountsEndpoint as c, sanitizeRedirectPath as d, createMemorySessionStore as i, fetchUserInfo as l, SessionCookies as n, GuardResult as o, createAccountsAuth as r, cacheCookieBase as s, AccountsAuth as t, requestOrigin as u };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import { a as
|
|
3
|
-
export { AccountsAuth, type AccountsAuthConfig, type AccountsLifetimes, type AccountsPaths, AccountsRequestError, type AccountsSession, type AccountsSessionPatch, type AccountsSessionStore, type AccountsTokens, type AccountsUser, type GuardOptions, type GuardResult, OAuthTokenError, type RevalidateInput, type SignInInput, accountsEndpoint, createAccountsAuth, createMemorySessionStore, requestOrigin, sanitizeRedirectPath };
|
|
1
|
+
import { a as AccountsRequestError, c as AccountsSessionStore, d as OAuthTokenError, i as AccountsPaths, l as AccountsTokens, m as SignInInput, n as AccountsCacheConfig, o as AccountsSession, p as RevalidateInput, r as AccountsLifetimes, s as AccountsSessionPatch, t as AccountsAuthConfig, u as AccountsUser } from "./types-C79_29ZY.js";
|
|
2
|
+
import { a as GuardOptions, c as accountsEndpoint, d as sanitizeRedirectPath, i as createMemorySessionStore, l as fetchUserInfo, n as SessionCookies, o as GuardResult, r as createAccountsAuth, s as cacheCookieBase, t as AccountsAuth, u as requestOrigin } from "./index-CiWgJQWW.js";
|
|
3
|
+
export { AccountsAuth, type AccountsAuthConfig, type AccountsCacheConfig, type AccountsLifetimes, type AccountsPaths, AccountsRequestError, type AccountsSession, type AccountsSessionPatch, type AccountsSessionStore, type AccountsTokens, type AccountsUser, type GuardOptions, type GuardResult, OAuthTokenError, type RevalidateInput, SessionCookies, type SignInInput, accountsEndpoint, cacheCookieBase, createAccountsAuth, createMemorySessionStore, fetchUserInfo, requestOrigin, sanitizeRedirectPath };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{C as e,E as t,S as n,T as r,_ as i,a,b as o,c as s,d as c,f as l,g as u,h as d,i as f,l as p,m,n as h,o as g,p as _,r as v,s as y,t as b,u as x,w as S,x as C,y as w}from"./cache-DuVjR2sZ.js";function T(t,r){return async function(e,i={}){let o=new URL(e.url);if((i.publicPaths??[t.paths.login,t.paths.callback,t.paths.error]).some(e=>o.pathname.startsWith(e)))return{kind:`ok`,session:null};let s=n(e,t.cookieName),c=n(e,h(t.cookieName)),l=await f(t,c,s,t.now());if(l)return{kind:`ok`,session:l};let u=s!==null||c!==null,d=await r.load(s);if(!d)return a(e,i,u);let p=d;try{let t=await r.revalidate(d);if(!t)return a(e,i,!0);p=t}catch{return{kind:`ok`,session:p}}if(p.tokens.accessTokenExpiresAt<=t.now()){let t=await r.ensureFreshTokens(p).catch(()=>p);if(!t)return a(e,i,!0);p=t}let m=await v(t,p,S(e),t.now());return m?{kind:`ok`,session:p,cookies:[m]}:{kind:`ok`,session:p}};function a(n,r,i){let a=S(n),s=new URL(n.url);if((r.apiPaths??[`/api`,`/trpc`]).some(e=>s.pathname.startsWith(e))){let e=Response.json({error:`Unauthorized`},{status:401});return i&&o(e,a),{kind:`response`,response:e}}let c=r.redirectPath?.(n)??`${s.pathname}${s.search}`,l=new URL(t.paths.login,a);l.searchParams.set(`redirect`,c),i&&l.searchParams.set(`silent`,`1`);let u=e(l);return i&&o(u,a),{kind:`response`,response:u}}function o(e,n){i(e.headers,t.cookieName,n);for(let r of b(t,n))e.headers.append(`set-cookie`,r)}}const E=/^[A-Za-z0-9_-]{1,128}$/,D=new Set([`login_required`,`consent_required`,`interaction_required`,`account_selection_required`]);function O(a,c){function l(e,t){let n=new URL(a.paths.login,e);return n.searchParams.set(`redirect`,t),n}function u(e,t,n){let r=new URL(a.paths.error,e);return r.searchParams.set(`reason`,t),n&&r.searchParams.set(`description`,n),r}async function f(n){let i=S(n),s=new URL(n.url).searchParams,c=r(s.get(`redirect`),i),l=s.get(`silent`)===`1`,{url:u,state:d,verifier:f}=await g(a,{origin:i,silent:l}),p=e(u);return t(p.headers,C(a.cookieName,d),o({verifier:f,redirectPath:c,silent:l}),i,a.lifetimes.flowMaxAgeMs),p}async function m(o){let f=S(o),m=new URL(o.url).searchParams,h=m.get(`state`),g=h&&E.test(h)?C(a.cookieName,h):null,y=g?w(n(o,g)):null,x=e=>(g&&i(e.headers,g,f),e);if(!y)return x(e(u(f,`invalid_state`,null)));let T=r(y.redirectPath,f),O=m.get(`error`);if(O)return y.silent&&D.has(O)?x(e(l(f,T))):x(e(u(f,O,m.get(`error_description`))));let k=m.get(`code`);if(!k)return x(e(u(f,`invalid_request`,null)));let A,j,M;try{let e=await s(a,{code:k,verifier:y.verifier,redirectUri:new URL(a.paths.callback,f).toString()});A=_(e,null,a.now()),j=await p(a,A.accessToken),M=await a.onSignIn({user:j,accessToken:A.accessToken,redirectPath:T,previous:null})}catch(t){return t instanceof d?x(e(u(f,t.code,t.description||null))):x(e(u(f,`accounts_unavailable`,null)))}if(M===null){let t=e(u(f,`access_denied`,null)),r=n(o,a.cookieName),s=await c.load(r);s&&await c.end(s),r!==null&&i(t.headers,a.cookieName,f);for(let e of b(a,f))t.headers.append(`set-cookie`,e);return x(t)}let N,P;try{({cookieValue:N,session:P}=await c.start({user:j,tokens:A,data:M}))}catch{return x(e(u(f,`session_store_error`,null)))}let F=e(new URL(T,f));t(F.headers,a.cookieName,N,f,a.lifetimes.absoluteMaxAgeMs);let I=await v(a,P,f,a.now()).catch(()=>null);return I&&F.headers.append(`set-cookie`,I),x(F)}async function h(t){let r=S(t),o=await c.load(n(t,a.cookieName));o&&await c.end(o);let s=o?.tokens.idToken?y(a,{origin:r,idToken:o.tokens.idToken}):new URL(a.paths.logoutComplete,r).toString(),l=e(s,303);i(l.headers,a.cookieName,r);for(let e of b(a,r))l.headers.append(`set-cookie`,e);return l}return{login:f,callback:m,logout:h}}const k=e=>new Promise(t=>setTimeout(t,e));function A(e){let{store:t,lifetimes:n}=e;function r(e,t){return t-e.createdAt>=n.absoluteMaxAgeMs||t-e.lastValidatedAt>=n.idleMaxAgeMs}function i(e,t){return e.accessTokenExpiresAt-t<=n.refreshBeforeExpiryMs}async function a(n){if(!n)return null;let i=await t.read(await l(n));return i?r(i,e.now())?(await t.delete(i.id),null):i:null}async function o(n){let r=x(32),i=e.now(),a={id:await l(r),user:n.user,tokens:n.tokens,data:n.data,createdAt:i,lastValidatedAt:i,refreshLeaseUntil:null};return await t.create(a),{session:a,cookieValue:r}}async function s(r){let a=e.now();if(!i(r.tokens,a))return r;if(!r.tokens.refreshToken)return await t.delete(r.id),null;let o=await t.claimRefreshLease(r.id,a+n.refreshLeaseMs,a);if(!o)return u(r.id,a);let s=o.refreshLeaseUntil??void 0;if(!i(o.tokens,a))return await t.update(o.id,{refreshLeaseUntil:null},s)??t.read(o.id);try{let r=await c(e,o.tokens.refreshToken,Math.max(n.refreshLeaseMs-1e3,n.refreshLeaseMs/2));return await t.update(o.id,{tokens:_(r,o.tokens,e.now()),refreshLeaseUntil:null},s)??t.read(o.id)}catch(n){if(n instanceof d&&n.code===`invalid_grant`)return await t.delete(o.id,s),await t.read(o.id)??null;let r=await t.update(o.id,{refreshLeaseUntil:null},s);if(o.tokens.accessTokenExpiresAt>e.now())return r??o;throw n}}async function u(r,a){for(;;){await k(100);let o=await t.read(r);if(!o)return null;let c=e.now();if(!i(o.tokens,c))return o;if(o.refreshLeaseUntil===null||o.refreshLeaseUntil<=c)return s(o);if(c-a>=n.leaseWaitMs){if(o.tokens.accessTokenExpiresAt>c)return o;throw new m(`Timed out waiting for the session refresh lease`,0)}}}async function f(r){if(e.now()-r.lastValidatedAt<n.revalidateIntervalMs)return r;let i=await s(r);if(!i)return null;let a=await e.onRevalidate({session:i,accessToken:i.tokens.accessToken});return a===null?(await t.delete(i.id),null):t.update(i.id,{data:a,lastValidatedAt:e.now()})}async function p(e){await t.delete(e.id)}return{load:a,start:o,ensureFreshTokens:s,revalidate:f,end:p}}function j(){let e=new Map;return{rows:e,async create(t){e.set(t.id,structuredClone(t))},async read(t){let n=e.get(t);return n?structuredClone(n):null},async update(t,n,r){let i=e.get(t);if(!i||r!==void 0&&i.refreshLeaseUntil!==r)return null;let a=structuredClone({...i,...n});return e.set(t,a),structuredClone(a)},async claimRefreshLease(t,n,r){let i=e.get(t);if(!i||i.refreshLeaseUntil!==null&&i.refreshLeaseUntil>r)return null;let a={...i,refreshLeaseUntil:n};return e.set(t,a),structuredClone(a)},async delete(t,n){let r=e.get(t);r&&(n===void 0||r.refreshLeaseUntil===n)&&e.delete(t)}}}function M(e){let t=u(e),r=A(t),i=O(t,r),a=T(t,r);function o(e){return{session:n(e,t.cookieName),cache:n(e,h(t.cookieName))}}async function s(e){return r.load(e)}async function c(e){return await f(t,e.cache,e.session,t.now())??r.load(e.session)}async function l(e){return c(o(e))}async function d(e){let t=await r.load(e);return t?(await r.ensureFreshTokens(t))?.tokens.accessToken??null:null}async function p(e){let n=await f(t,e.cache,e.session,t.now());return n&&n.tokens.accessTokenExpiresAt-t.now()>t.lifetimes.refreshBeforeExpiryMs?n.tokens.accessToken:d(e.session)}async function m(e){return p(o(e))}async function g(e,n){let i=await r.load(e);return i?t.store.update(i.id,{data:n(i.data)}):null}return{config:t,sessions:r,handlers:i,guard:a,sessionFromCookie:s,sessionFromCookies:c,sessionFromRequest:l,accessTokenFromCookie:d,accessTokenFromCookies:p,accessTokenFromRequest:m,updateSessionData:g}}export{m as AccountsRequestError,d as OAuthTokenError,a as accountsEndpoint,h as cacheCookieBase,M as createAccountsAuth,j as createMemorySessionStore,p as fetchUserInfo,S as requestOrigin,r as sanitizeRedirectPath};
|
package/dist/next.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as AccountsAuth } from "./index-
|
|
3
|
-
//#region src/next.d.ts
|
|
1
|
+
import { o as AccountsSession } from "./types-C79_29ZY.js";
|
|
2
|
+
import { t as AccountsAuth } from "./index-CiWgJQWW.js";
|
|
3
|
+
//#region src/next/index.d.ts
|
|
4
4
|
declare function withNextRequestScope<Data>(auth: AccountsAuth<Data>): {
|
|
5
5
|
getSession(): Promise<AccountsSession<Data> | null>;
|
|
6
6
|
getAccessToken(): Promise<string | null>;
|
package/dist/next.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e}from"./
|
|
1
|
+
import{n as e,v as t}from"./cache-DuVjR2sZ.js";import{cookies as n}from"next/headers";async function r(r){let i=await n(),a=e=>i.get(t(e,!0))?.value||i.get(t(e,!1))?.value||null;return{session:a(r),cache:a(e(r))}}async function i(r){let i=await n(),a=e(r);for(let e of[t(a,!0),t(a,!1)])try{i.delete(e)}catch{}}function a(e){let t=e.config.cookieName;return{async getSession(){return e.sessionFromCookies(await r(t))},async getAccessToken(){return e.accessTokenFromCookies(await r(t))},async updateSessionData(n){let a=await e.updateSessionData((await r(t)).session,n);return a&&await i(t),a}}}export{a as withNextRequestScope};
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
//#region src/
|
|
1
|
+
//#region src/core/codec.d.ts
|
|
2
|
+
type SessionCodec = {
|
|
3
|
+
encrypt(value: string): Promise<string>;
|
|
4
|
+
decrypt(value: string): Promise<string>;
|
|
5
|
+
};
|
|
6
|
+
declare function createAesGcmCodec(hexKey: string): SessionCodec;
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region src/core/types.d.ts
|
|
2
9
|
type AccountsUser = {
|
|
3
10
|
id: string;
|
|
4
11
|
email: string;
|
|
@@ -67,13 +74,24 @@ type AccountsAuthConfig<Data> = {
|
|
|
67
74
|
onRevalidate(input: RevalidateInput<Data>): Promise<Data | null>;
|
|
68
75
|
fetch?: typeof fetch;
|
|
69
76
|
now?: () => number;
|
|
77
|
+
cache?: AccountsCacheConfig;
|
|
78
|
+
audience?: string | false;
|
|
79
|
+
};
|
|
80
|
+
type AccountsCacheConfig = {
|
|
81
|
+
secret: string;
|
|
82
|
+
maxAgeMs?: number;
|
|
70
83
|
};
|
|
71
|
-
type ResolvedAccountsAuthConfig<Data> = Omit<AccountsAuthConfig<Data>, "paths" | "lifetimes" | "scope" | "fetch" | "now"> & {
|
|
84
|
+
type ResolvedAccountsAuthConfig<Data> = Omit<AccountsAuthConfig<Data>, "paths" | "lifetimes" | "scope" | "fetch" | "now" | "cache" | "audience"> & {
|
|
72
85
|
scope: string;
|
|
73
86
|
paths: AccountsPaths;
|
|
74
87
|
lifetimes: AccountsLifetimes;
|
|
75
88
|
fetch: typeof fetch;
|
|
76
89
|
now: () => number;
|
|
90
|
+
cache: {
|
|
91
|
+
codec: () => Promise<SessionCodec>;
|
|
92
|
+
maxAgeMs: number;
|
|
93
|
+
} | null;
|
|
94
|
+
audience: string | null;
|
|
77
95
|
};
|
|
78
96
|
declare class AccountsRequestError extends Error {
|
|
79
97
|
readonly status: number;
|
|
@@ -81,7 +99,8 @@ declare class AccountsRequestError extends Error {
|
|
|
81
99
|
}
|
|
82
100
|
declare class OAuthTokenError extends AccountsRequestError {
|
|
83
101
|
readonly code: string;
|
|
102
|
+
readonly description: string;
|
|
84
103
|
constructor(status: number, code: string, description: string);
|
|
85
104
|
}
|
|
86
105
|
//#endregion
|
|
87
|
-
export {
|
|
106
|
+
export { AccountsRequestError as a, AccountsSessionStore as c, OAuthTokenError as d, ResolvedAccountsAuthConfig as f, createAesGcmCodec as g, SessionCodec as h, AccountsPaths as i, AccountsTokens as l, SignInInput as m, AccountsCacheConfig as n, AccountsSession as o, RevalidateInput as p, AccountsLifetimes as r, AccountsSessionPatch as s, AccountsAuthConfig as t, AccountsUser as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aui-auth",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Server side sessions for web apps that sign in through assistant-ui accounts: OIDC code flow with PKCE, tokens kept in the app's database, single flight refresh",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -13,17 +13,21 @@
|
|
|
13
13
|
"types": "./dist/index.d.ts",
|
|
14
14
|
"default": "./dist/index.js"
|
|
15
15
|
},
|
|
16
|
+
"./accounts": {
|
|
17
|
+
"types": "./dist/accounts.d.ts",
|
|
18
|
+
"default": "./dist/accounts.js"
|
|
19
|
+
},
|
|
16
20
|
"./next": {
|
|
17
21
|
"types": "./dist/next.d.ts",
|
|
18
22
|
"default": "./dist/next.js"
|
|
19
23
|
},
|
|
20
|
-
"./
|
|
21
|
-
"types": "./dist/
|
|
22
|
-
"default": "./dist/
|
|
24
|
+
"./database": {
|
|
25
|
+
"types": "./dist/database/index.d.ts",
|
|
26
|
+
"default": "./dist/database/index.js"
|
|
23
27
|
},
|
|
24
|
-
"./
|
|
25
|
-
"types": "./dist/
|
|
26
|
-
"default": "./dist/
|
|
28
|
+
"./database/pg": {
|
|
29
|
+
"types": "./dist/database/pg.d.ts",
|
|
30
|
+
"default": "./dist/database/pg.js"
|
|
27
31
|
}
|
|
28
32
|
},
|
|
29
33
|
"peerDependencies": {
|
package/dist/cookies-D3lpM5ER.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
function e(e){if(!e)return;let t=e.split(`,`);return t[t.length-1].trim()||void 0}function t(t){let n=new URL(t.url);return`${e(t.headers.get(`x-forwarded-proto`))||n.protocol.replace(`:`,``)}://${e(t.headers.get(`x-forwarded-host`))||t.headers.get(`host`)||n.host}`}function n(e){return new URL(e).protocol===`https:`}function r(e,t){return t?`__Secure-${e}`:e}function i(e){let t=new Map;if(!e)return t;for(let n of e.split(`;`)){let e=n.indexOf(`=`);if(e===-1)continue;let r=n.slice(0,e).trim();!r||t.has(r)||t.set(r,n.slice(e+1).trim())}return t}function a(e,t){let n=i(e.headers.get(`cookie`));return n.get(r(t,!0))||n.get(r(t,!1))||null}function o(e,t,n,r){let i=[`${e}=${t}`,`Path=/`,`HttpOnly`,`SameSite=Lax`,`Max-Age=${r}`];return n&&i.push(`Secure`),i.join(`; `)}function s(e,t,i,a,s){let c=n(a);e.append(`set-cookie`,o(r(t,c),i,c,Math.floor(s/1e3)))}function c(e,t,i){let a=n(i);for(let n of[a,!a])e.append(`set-cookie`,o(r(t,n),``,n,0))}function l(e,t=307){return new Response(null,{status:t,headers:{location:e.toString()}})}function u(e,t){return`${e}_flow_${t}`}function d(e){return btoa(JSON.stringify(e)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/g,``)}function f(e){if(!e)return null;try{let t=e.replace(/-/g,`+`).replace(/_/g,`/`),n=JSON.parse(atob(t));return typeof n.verifier==`string`?{verifier:n.verifier,redirectPath:typeof n.redirectPath==`string`?n.redirectPath:`/`,silent:n.silent===!0}:null}catch{return null}}function p(e,t){if(!e)return`/`;let n;try{n=new URL(e,t)}catch{return`/`}return n.origin===t?`${n.pathname}${n.search}${n.hash}`:`/`}export{u as a,t as c,d as i,p as l,r as n,a as o,f as r,l as s,c as t,s as u};
|
package/dist/oidc-BIfcHoyS.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const e={login:`/api/auth/login`,callback:`/api/auth/callback`,logout:`/api/auth/logout`,logoutComplete:`/api/auth/logout-complete`,error:`/auth/error`},t={absoluteMaxAgeMs:2592e6,idleMaxAgeMs:6048e5,revalidateIntervalMs:12e4,refreshBeforeExpiryMs:3e5,flowMaxAgeMs:6e5,refreshLeaseMs:2e4,leaseWaitMs:5e3};function n(n){return{...n,scope:n.scope??`openid profile email offline_access`,paths:{...e,...n.paths},lifetimes:{...t,...n.lifetimes},fetch:n.fetch??globalThis.fetch.bind(globalThis),now:n.now??Date.now}}var r=class extends Error{status;constructor(e,t){super(e),this.name=`AccountsRequestError`,this.status=t}},i=class extends r{code;constructor(e,t,n){super(`Token request failed: ${e} ${t} ${n}`,e),this.name=`OAuthTokenError`,this.code=t}};function a(e){let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/g,``)}function o(e){return a(crypto.getRandomValues(new Uint8Array(e)))}async function s(e){let t=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(e));return a(new Uint8Array(t))}function c(e,t){return new URL(t,e).toString()}async function l(e,t){let n=o(24),r=o(32),i=new URL(c(e.issuer,`/api/auth/oauth2/authorize`));return i.searchParams.set(`client_id`,e.clientId),i.searchParams.set(`redirect_uri`,new URL(e.paths.callback,t.origin).toString()),i.searchParams.set(`response_type`,`code`),i.searchParams.set(`scope`,e.scope),i.searchParams.set(`state`,n),i.searchParams.set(`code_challenge`,await s(r)),i.searchParams.set(`code_challenge_method`,`S256`),t.silent&&i.searchParams.set(`prompt`,`none`),{url:i.toString(),state:n,verifier:r}}function u(e,t){let n=new URL(c(e.issuer,`/api/auth/oauth2/end-session`));return n.searchParams.set(`id_token_hint`,t.idToken),n.searchParams.set(`client_id`,e.clientId),n.searchParams.set(`post_logout_redirect_uri`,new URL(e.paths.logoutComplete,t.origin).toString()),n.toString()}async function d(e,t,n){let r=new URLSearchParams({client_id:e.clientId,...t});e.clientSecret&&r.set(`client_secret`,e.clientSecret);let a=await e.fetch(c(e.issuer,`/api/auth/oauth2/token`),{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:r,cache:`no-store`,...n?{signal:AbortSignal.timeout(n)}:{}});if(!a.ok){let e=await a.text().catch(()=>``),t=`unknown_error`,n=e;try{let r=JSON.parse(e);t=r.error??t,n=r.error_description??n}catch{}throw new i(a.status,t,n)}return await a.json()}function f(e,t){return d(e,{grant_type:`authorization_code`,code:t.code,code_verifier:t.verifier,redirect_uri:t.redirectUri})}function p(e,t,n){return d(e,{grant_type:`refresh_token`,refresh_token:t},n)}async function m(e,t){let n=await e.fetch(c(e.issuer,`/api/auth/oauth2/userinfo`),{headers:{Authorization:`Bearer ${t}`},cache:`no-store`});if(!n.ok)throw new r(`Failed to load user info: ${n.status}`,n.status);let i=await n.json();return{id:i.sub,email:i.email??``,name:i.name??i.email??i.sub,image:i.picture??null}}function h(e,t,n){return{accessToken:e.access_token,refreshToken:e.refresh_token??t?.refreshToken??null,idToken:e.id_token??t?.idToken??null,accessTokenExpiresAt:typeof e.expires_at==`number`?e.expires_at*1e3:n+(e.expires_in??3600)*1e3}}export{m as a,s as c,i as d,n as f,f as i,h as l,l as n,o,u as r,p as s,c as t,r as u};
|