aui-auth 0.0.7 → 0.0.8

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/accounts.js CHANGED
@@ -1 +1 @@
1
- import{a as e,t}from"./types-B_7rFOLg.js";import{n}from"./oidc-CDcBo0qB.js";async function r(e,r){let i=await n(e,`/api/oidc/organizations`,{headers:{Authorization:`Bearer ${r}`}});if(!i.ok)throw new t(`Failed to load organizations: ${i.status}`,i.status);return await i.json()}function i(e,t){if(t){let n=e.find(e=>e.slug===t);if(n)return n}return e[0]??null}function a(e){let[,t]=new URL(e,`http://localhost`).pathname.split(`/`);return t&&t!==`org`?t:null}function o(t){let n=t.preferredSlug??a;async function o(e){return{activeOrganization:i(await r(t,e.accessToken),n(e.redirectPath))}}async function s(n){let a;try{a=await r(t,n.accessToken)}catch(t){if(e(t))return null;throw t}let o=n.session.data.activeOrganization;if(!o)return{activeOrganization:i(a)};let s=a.find(e=>e.id===o.id)??null;return s?{activeOrganization:s}:null}return{onSignIn:o,onRevalidate:s}}export{r as fetchOrganizations,o as organizationHooks,a as preferredOrganizationSlug,i as selectOrganization};
1
+ import{a as e,t}from"./types-B_7rFOLg.js";import{n}from"./oidc-0pw9wXd4.js";async function r(e,r){let i=await n(e,`/api/oidc/organizations`,{headers:{Authorization:`Bearer ${r}`}});if(!i.ok)throw new t(`Failed to load organizations: ${i.status}`,i.status);return await i.json()}function i(e,t){if(t){let n=e.find(e=>e.slug===t);if(n)return n}return e[0]??null}function a(e){let[,t]=new URL(e,`http://localhost`).pathname.split(`/`);return t&&t!==`org`?t:null}function o(t){let n=t.preferredSlug??a;async function o(e){return{activeOrganization:i(await r(t,e.accessToken),n(e.redirectPath))}}async function s(n){let a;try{a=await r(t,n.accessToken)}catch(t){if(e(t))return null;throw t}let o=n.session.data.activeOrganization;if(!o)return{activeOrganization:i(a)};let s=a.find(e=>e.id===o.id)??null;return s?{activeOrganization:s}:null}return{onSignIn:o,onRevalidate:s}}export{r as fetchOrganizations,o as organizationHooks,a as preferredOrganizationSlug,i as selectOrganization};
@@ -1 +1 @@
1
- import{o as e}from"./types-B_7rFOLg.js";import{d as t}from"./oidc-CDcBo0qB.js";function n(e){if(!e)return;let t=e.split(`,`);return t[t.length-1].trim()||void 0}function r(e){let t=new URL(e.url);return`${n(e.headers.get(`x-forwarded-proto`))||t.protocol.replace(`:`,``)}://${n(e.headers.get(`x-forwarded-host`))||e.headers.get(`host`)||t.host}`}function i(e){return new URL(e).protocol===`https:`}function a(e,t){return t?`__Secure-${e}`:e}function o(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 s(e,t){let n=o(e.headers.get(`cookie`));return n.get(a(t,!0))||n.get(a(t,!1))||null}function c(e,t,n,r){let i=[`${e}=${t}`,`Path=/`,`HttpOnly`,`SameSite=Lax`,`Max-Age=${r}`];return n&&i.push(`Secure`),i.join(`; `)}function l(e,t,n,r,o){let s=i(r);e.append(`set-cookie`,c(a(t,s),n,s,Math.floor(o/1e3)))}function u(e,t){if(t.length===0)return;let n=o(e.get(`cookie`));for(let e of t){let t=e.split(`;`)[0],r=t.indexOf(`=`);if(r<1)continue;let i=t.slice(0,r).trim(),a=t.slice(r+1).trim();a?n.set(i,a):n.delete(i)}e.set(`cookie`,[...n].map(([e,t])=>`${e}=${t}`).join(`; `))}function d(e,t){let n=i(t);return[n,!n].map(t=>c(a(e,t),``,t,0))}function f(e,t,n){for(let r of d(t,n))e.append(`set-cookie`,r)}function p(e,t=307){return new Response(null,{status:t,headers:{location:e.toString()}})}function m(e,t){return`${e}_flow_${t}`}function h(e){return btoa(JSON.stringify(e)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/g,``)}function g(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 _(e,t){if(!e)return`/`;let n;try{n=new URL(e,t)}catch{return`/`}return n.origin!==t||n.pathname.startsWith(`//`)?`/`:`${n.pathname}${n.search}${n.hash}`}const v=4096;function y(e){return`${e}_cache`}function b(e,t,n){if(!e.cache)return 0;let{lifetimes:r}=e,i=Math.min(t.lastValidatedAt+r.revalidateIntervalMs,t.tokens.accessTokenExpiresAt-r.refreshBeforeExpiryMs);return Math.min(e.cache.maxAgeMs,(i>n?i:n+r.retryIntervalMs)-n,t.createdAt+r.absoluteMaxAgeMs-n,t.lastValidatedAt+r.idleMaxAgeMs-n)}async function x(e,t,n){if(!e.cache)return null;let r=b(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 S(e,n,r,i){if(!e.cache||!n||!r)return null;let a;try{let t=await e.cache.codec();a=JSON.parse(await t.decrypt(n))}catch{return null}return a.v!==1||typeof a.exp!=`number`||a.exp<=i||a.id!==await t(r)?null:{id:a.id,user:a.u,tokens:{accessToken:a.at,refreshToken:null,idToken:null,accessTokenExpiresAt:a.ate},data:a.d,createdAt:a.ca,lastValidatedAt:a.lv,refreshLeaseUntil:null}}async function C(t,n,r,o){try{let e=await x(t,n,o);if(!e)return null;let s=i(r),l=c(a(y(t.cookieName),s),e.value,s,Math.floor(e.maxAgeMs/1e3));if(l.length>v)throw Error(`Cache cookie is ${l.length} bytes and browsers drop cookies over ${v}; the session data is too large to cache`);return l}catch(n){return e(t,`cache_cookie`,n),null}}function w(e,t){return e.cache?d(y(e.cookieName),t):[]}export{c as _,f as a,g as c,u as d,o as f,_ as g,r as h,S as i,h as l,p as m,y as n,d as o,s as p,C as r,a as s,w as t,m as u,l as v};
1
+ import{o as e}from"./types-B_7rFOLg.js";import{p as t}from"./oidc-0pw9wXd4.js";function n(e){if(!e)return;let t=e.split(`,`);return t[t.length-1].trim()||void 0}function r(e){let t=new URL(e.url);return`${n(e.headers.get(`x-forwarded-proto`))||t.protocol.replace(`:`,``)}://${n(e.headers.get(`x-forwarded-host`))||e.headers.get(`host`)||t.host}`}function i(e){return new URL(e).protocol===`https:`}function a(e,t){return t?`__Secure-${e}`:e}function o(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 s(e,t){let n=o(e.headers.get(`cookie`));return n.get(a(t,!0))||n.get(a(t,!1))||null}function c(e,t,n,r){let i=[`${e}=${t}`,`Path=/`,`HttpOnly`,`SameSite=Lax`,`Max-Age=${r}`];return n&&i.push(`Secure`),i.join(`; `)}function l(e,t,n,r,o){let s=i(r);e.append(`set-cookie`,c(a(t,s),n,s,Math.floor(o/1e3)))}function u(e,t){if(t.length===0)return;let n=o(e.get(`cookie`));for(let e of t){let t=e.split(`;`)[0],r=t.indexOf(`=`);if(r<1)continue;let i=t.slice(0,r).trim(),a=t.slice(r+1).trim();a?n.set(i,a):n.delete(i)}e.set(`cookie`,[...n].map(([e,t])=>`${e}=${t}`).join(`; `))}function d(e,t){let n=i(t);return[n,!n].map(t=>c(a(e,t),``,t,0))}function f(e,t,n){for(let r of d(t,n))e.append(`set-cookie`,r)}function p(e,t=307){return new Response(null,{status:t,headers:{location:e.toString()}})}function m(e,t){return`${e}_flow_${t}`}function h(e){return btoa(JSON.stringify(e)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/g,``)}function g(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 _(e,t){if(!e)return`/`;let n;try{n=new URL(e,t)}catch{return`/`}return n.origin!==t||n.pathname.startsWith(`//`)?`/`:`${n.pathname}${n.search}${n.hash}`}const v=4096;function y(e){return`${e}_cache`}function b(e,t,n){if(!e.cache)return 0;let{lifetimes:r}=e,i=Math.min(t.lastValidatedAt+r.revalidateIntervalMs,t.tokens.accessTokenExpiresAt-r.refreshBeforeExpiryMs);return Math.min(e.cache.maxAgeMs,(i>n?i:n+r.retryIntervalMs)-n,t.createdAt+r.absoluteMaxAgeMs-n,t.lastValidatedAt+r.idleMaxAgeMs-n)}async function x(e,t,n){if(!e.cache)return null;let r=b(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 S(e,n,r,i){if(!e.cache||!n||!r)return null;let a;try{let t=await e.cache.codec();a=JSON.parse(await t.decrypt(n))}catch{return null}return a.v!==1||typeof a.exp!=`number`||a.exp<=i||a.id!==await t(r)?null:{id:a.id,user:a.u,tokens:{accessToken:a.at,refreshToken:null,idToken:null,accessTokenExpiresAt:a.ate},data:a.d,createdAt:a.ca,lastValidatedAt:a.lv,refreshLeaseUntil:null}}async function C(t,n,r,o){try{let e=await x(t,n,o);if(!e)return null;let s=i(r),l=c(a(y(t.cookieName),s),e.value,s,Math.floor(e.maxAgeMs/1e3));if(l.length>v)throw Error(`Cache cookie is ${l.length} bytes and browsers drop cookies over ${v}; the session data is too large to cache`);return l}catch(n){return e(t,`cache_cookie`,n),null}}function w(e,t){return e.cache?d(y(e.cookieName),t):[]}export{c as _,f as a,g as c,u as d,o as f,_ as g,r as h,S as i,h as l,p as m,y as n,d as o,s as p,C as r,a as s,w as t,m as u,l as v};
@@ -0,0 +1,69 @@
1
+ import { d as AccountsTokens, f as AccountsUser, m as OAuthTokenError, s as AccountsRequestError, y as isAccessDenied } from "./types-Cx223pmJ.js";
2
+ //#region src/device/index.d.ts
3
+ declare const DEVICE_CODE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
4
+ type DeviceLoginConfig = {
5
+ issuer: string;
6
+ clientId: string;
7
+ scope?: string;
8
+ /**
9
+ * The resource the tokens are minted for; `<issuer>/api/auth` unless set,
10
+ * `false` for opaque tokens. Sent with the device code request, so the
11
+ * approval binds it, and again when the code is redeemed.
12
+ */
13
+ audience?: string | false;
14
+ /** How close to expiry `ensureFresh` refreshes; five minutes by default. */
15
+ refreshBeforeExpiryMs?: number;
16
+ requestTimeoutMs?: number;
17
+ fetch?: typeof fetch;
18
+ now?: () => number;
19
+ /** The wait between polls, for tests; a plain timer otherwise. */
20
+ sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
21
+ };
22
+ type DeviceAuthorization = {
23
+ deviceCode: string;
24
+ userCode: string;
25
+ verificationUri: string;
26
+ verificationUriComplete: string;
27
+ expiresAt: number;
28
+ intervalMs: number;
29
+ /** The resource the approval binds; null when the provider refused it. */
30
+ resource: string | null;
31
+ };
32
+ type DeviceCredentials = {
33
+ user: AccountsUser;
34
+ tokens: AccountsTokens;
35
+ };
36
+ /**
37
+ * The RFC 8628 device authorization grant against accounts, for a CLI or any
38
+ * process without a browser of its own: `start` asks for a code, the person
39
+ * approves it on the accounts device page, `wait` polls the token endpoint
40
+ * until the approval lands, and `refresh` and `ensureFresh` keep the token set
41
+ * alive afterwards. The credentials the flow hands back belong to the device,
42
+ * not to the browser session that approved them, so they outlive it. Where
43
+ * they are stored is the app's decision.
44
+ */
45
+ declare function createDeviceLogin(config: DeviceLoginConfig): {
46
+ /** Asks accounts for a device code and the user code to show. */
47
+ start(): Promise<DeviceAuthorization>;
48
+ /**
49
+ * Polls until the person approves, at the interval accounts asked for
50
+ * (`slow_down` adds five seconds), and resolves with the token set and the
51
+ * profile from userinfo. Rejects with `OAuthTokenError` `access_denied`
52
+ * when the person refuses and `expired_token` when nobody answers in time.
53
+ */
54
+ wait(authorization: DeviceAuthorization, options?: {
55
+ signal?: AbortSignal;
56
+ }): Promise<DeviceCredentials>;
57
+ /**
58
+ * Spends the refresh token for a new token set. accounts rotates the
59
+ * refresh token on every use, so the credentials this resolves with
60
+ * replace the ones passed in. A rejection that `isAccessDenied` accepts
61
+ * means the login is over; anything else says nothing about it.
62
+ */
63
+ refresh(credentials: DeviceCredentials): Promise<DeviceCredentials>;
64
+ /** The credentials as they are while the access token has time left, refreshed otherwise. */
65
+ ensureFresh(credentials: DeviceCredentials): Promise<DeviceCredentials>;
66
+ };
67
+ type DeviceLogin = ReturnType<typeof createDeviceLogin>;
68
+ //#endregion
69
+ export { AccountsRequestError, type AccountsTokens, type AccountsUser, DEVICE_CODE_GRANT_TYPE, DeviceAuthorization, DeviceCredentials, DeviceLogin, DeviceLoginConfig, OAuthTokenError, createDeviceLogin, isAccessDenied };
package/dist/device.js ADDED
@@ -0,0 +1 @@
1
+ import{a as e,n as t,r as n,t as r}from"./types-B_7rFOLg.js";import{c as i,d as a,f as o,h as s,m as c,n as l,r as u}from"./oidc-0pw9wXd4.js";const d=`urn:ietf:params:oauth:grant-type:device_code`;function f(e,t){return new Promise((n,r)=>{if(t?.aborted){r(t.reason??Error(`Device login aborted`));return}let i=setTimeout(()=>{t?.removeEventListener(`abort`,a),n()},e);function a(){clearTimeout(i),r(t?.reason??Error(`Device login aborted`))}t?.addEventListener(`abort`,a,{once:!0})})}function p(e){let r=e.now??Date.now,p=e.sleep??f,m=e.scope??`openid profile email offline_access`,h=e.audience===void 0?u(e.issuer):e.audience||null,g=e.refreshBeforeExpiryMs??t.refreshBeforeExpiryMs,_={issuer:e.issuer,fetch:e.fetch,timeoutMs:e.requestTimeoutMs},v=t=>({..._,clientId:e.clientId,audience:t});async function y(t){let n=new URLSearchParams({client_id:e.clientId,scope:m});t&&n.set(`resource`,t);let i=await l(_,`/api/auth/device/code`,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:n});if(!i.ok){let e=await c(i);if(t&&a(e))return y(null);throw e}let o=await i.json();return{deviceCode:o.device_code,userCode:o.user_code,verificationUri:o.verification_uri,verificationUriComplete:o.verification_uri_complete,expiresAt:r()+o.expires_in*1e3,intervalMs:(o.interval??5)*1e3,resource:t}}async function b(e,t){let n=s(e,t?.tokens??null,r());return{user:t?.user??await i(_,n.accessToken),tokens:n}}return{start(){return y(h)},async wait(e,t={}){let i=e.intervalMs;for(;;){if(r()>=e.expiresAt)throw new n(400,`expired_token`,`The device code expired before it was approved`);await p(i,t.signal);try{return await b(await o(v(e.resource),{grant_type:d,device_code:e.deviceCode},void 0,e.resource!==null),null)}catch(e){if(e instanceof n){if(e.code===`authorization_pending`)continue;if(e.code===`slow_down`){i+=5e3;continue}}throw e}}},async refresh(e){let{refreshToken:t}=e.tokens;if(!t)throw new n(400,`invalid_grant`,`The credentials carry no refresh token`);return b(await o(v(h),{grant_type:`refresh_token`,refresh_token:t}),e)},async ensureFresh(e){return e.tokens.accessTokenExpiresAt-g>r()?e:this.refresh(e)}}}export{r as AccountsRequestError,d as DEVICE_CODE_GRANT_TYPE,n as OAuthTokenError,p as createDeviceLogin,e as isAccessDenied};
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{_ as e,a as t,c as n,d as r,f as i,g as a,h as o,i as s,l as c,m as l,n as u,o as d,p as f,r as p,t as m,u as h,v as g}from"./cache-DNvwg4aa.js";import{a as _,i as v,n as y,o as b,r as x,s as S,t as C}from"./types-B_7rFOLg.js";import{a as w,c as T,d as E,f as D,i as O,l as k,o as A,r as j,s as M,t as N,u as P}from"./oidc-CDcBo0qB.js";function F(e,t){return[...d(e.cookieName,t),...m(e,t)]}function I(e,t){return async function(n){let r=o(n),i=f(n,e.cookieName),a=f(n,u(e.cookieName)),c=await s(e,a,i,e.now());if(c)return{session:c,cookies:[]};let l={session:null,cookies:i!==null||a!==null?F(e,r):[]},d=await t.load(i);if(!d)return l;let{deferRevalidation:m}=e;if(m&&t.revalidationDue(d)&&L(e,m,t,d)){let t=await p(e,d,r,e.now());return{session:d,cookies:t?[t]:[]}}let h=d;try{let e=await t.revalidate(d);if(!e)return l;h=e}catch(t){b(e,`revalidate`,t)}let g=await p(e,h,r,e.now());return{session:h,cookies:g?[g]:[]}}}function L(e,t,n,r){try{return t(async()=>{try{await n.revalidate(r)}catch(t){b(e,`revalidate`,t)}}),!0}catch(t){return b(e,`revalidate`,t),!1}}function R(e,t){let n=I(e,t);return async function(t,i={}){let a=new URL(t.url);if([e.paths.login,e.paths.callback,e.paths.logout,e.paths.logoutComplete,e.paths.error,...i.publicPaths??[]].some(e=>a.pathname.startsWith(e)))return{kind:`ok`,session:null};let{session:o,cookies:s}=await n(t);return o?s.length>0?{kind:`ok`,session:o,cookies:s}:{kind:`ok`,session:o}:r(t,i,s)};function r(e,t,n){let r=n.length>0,a=new URL(e.url),o=(t.apiPaths??[`/api`,`/trpc`]).some(e=>a.pathname.startsWith(e))?Response.json({error:`Unauthorized`},{status:401}):l(i(e,t,r));for(let e of n)o.headers.append(`set-cookie`,e);return{kind:`response`,response:o}}function i(t,n,r){let i=new URL(t.url),a=new URL(e.paths.login,o(t));return a.searchParams.set(`redirect`,n.redirectPath?.(t)??`${i.pathname}${i.search}`),r&&a.searchParams.set(`silent`,`1`),a}}const z=/^[A-Za-z0-9_-]{1,128}$/,B=new Set([`login_required`,`consent_required`,`interaction_required`,`account_selection_required`]);function V(r,s){function u(e,t){let n=new URL(r.paths.login,e);return n.searchParams.set(`redirect`,t),n}function d(e,t,n){let i=new URL(r.paths.error,e);return i.searchParams.set(`reason`,t),n&&i.searchParams.set(`description`,n),i}function _(t,n){let a=h(r.cookieName,``),o=[...i(t.headers.get(`cookie`)).keys()].filter(e=>e.replace(/^__Secure-/,``).startsWith(a)),s=o.length-4;for(let t of o.slice(0,Math.max(0,s)))n.headers.append(`set-cookie`,e(t,``,t.startsWith(`__Secure-`),0))}async function v(e){try{let t=await s.load(e);t&&await s.end(t)}catch(e){b(r,`session_store`,e)}}async function y(e){let t=o(e),n=new URL(e.url).searchParams,i=a(n.get(`redirect`),t),s=n.get(`silent`)===`1`,{url:u,state:d,verifier:f}=await O(r,{origin:t,silent:s}),p=l(u);return _(e,p),g(p.headers,h(r.cookieName,d),c({verifier:f,redirectPath:i,silent:s}),t,r.lifetimes.flowMaxAgeMs),p}async function S(e){let i=o(e),c=new URL(e.url).searchParams,_=c.get(`state`),y=_&&z.test(_)?h(r.cookieName,_):null,S=y?n(f(e,y)):null,C=e=>(y&&t(e.headers,y,i),e);if(!S)return C(l(d(i,`invalid_state`,null)));let w=a(S.redirectPath,i),E=c.get(`iss`);if(E!==null&&E!==j(r.issuer))return C(l(d(i,`invalid_issuer`,null)));let O=c.get(`error`);if(O)return S.silent&&B.has(O)?C(l(u(i,w))):C(l(d(i,O,c.get(`error_description`))));let k=c.get(`code`);if(!k)return C(l(d(i,`invalid_request`,null)));let N,P,F;try{let e=await A(r,{code:k,verifier:S.verifier,redirectUri:new URL(r.paths.callback,i).toString()});N=D(e,null,r.now()),P=await T(M(r),N.accessToken),F=await r.onSignIn({user:P,accessToken:N.accessToken,redirectPath:w,previous:null})}catch(e){return b(r,`sign_in`,e),e instanceof x?C(l(d(i,e.code,e.description||null))):C(l(d(i,`accounts_unavailable`,null)))}let I=f(e,r.cookieName);if(F===null){let e=l(d(i,`access_denied`,null));I!==null&&(await v(I),t(e.headers,r.cookieName,i));for(let t of m(r,i))e.headers.append(`set-cookie`,t);return C(e)}let L,R;try{({cookieValue:L,session:R}=await s.start({user:P,tokens:N,data:F}))}catch(e){return b(r,`session_store`,e),C(l(d(i,`session_store_error`,null)))}I!==null&&await v(I);let V=l(new URL(w,i));g(V.headers,r.cookieName,L,i,r.lifetimes.absoluteMaxAgeMs);let H=await p(r,R,i,r.now());return H&&V.headers.append(`set-cookie`,H),C(V)}async function C(e){let t=o(e),n=await s.load(f(e,r.cookieName));n&&await s.end(n);let i=n?.tokens.idToken&&r.logout===`global`?w(r,{origin:t,idToken:n.tokens.idToken}):new URL(r.paths.logoutComplete,t).toString(),a=l(i,303);for(let e of F(r,t))a.headers.append(`set-cookie`,e);return a}return{login:y,callback:S,logout:C}}const H=e=>new Promise(t=>setTimeout(t,e));function U(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}function a(t){let r=e.now();return!i(t.tokens,r)&&r-t.lastValidatedAt>=n.revalidateIntervalMs}async function o(n){if(!n)return null;let i=await E(n),a;try{a=await t.read(i)}catch(n){if(!(n instanceof v))throw n;return b(e,`session_store`,n),await t.delete(i),null}return a?r(a,e.now())?(await t.delete(a.id),null):a:null}async function s(n){let r=k(32),i=e.now(),a={id:await E(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 c(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 l(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 P(e,o.tokens.refreshToken,Math.max(n.refreshLeaseMs-1e3,n.refreshLeaseMs/2));return await t.update(o.id,{tokens:D(r,o.tokens,e.now()),refreshLeaseUntil:null},s)??t.read(o.id)}catch(n){if(_(n))return await t.delete(o.id,s)?null:await t.read(o.id)??null;let r=await t.update(o.id,{refreshLeaseUntil:null},s);if(o.tokens.accessTokenExpiresAt>e.now())return b(e,`refresh`,n),r??o;throw n}}async function l(r,a){for(;;){await H(100);let o=await t.read(r);if(!o)return null;let s=e.now();if(!i(o.tokens,s))return o;if(o.refreshLeaseUntil===null||o.refreshLeaseUntil<=s)return c(o);if(s-a>=n.leaseWaitMs){if(o.tokens.accessTokenExpiresAt>s)return o;throw new C(`Timed out waiting for the session refresh lease`,0)}}}async function u(r){let i;try{i=await c(r)}catch(t){b(e,`refresh`,t),i=r}if(!i)return null;if(e.now()-i.lastValidatedAt<n.revalidateIntervalMs||!d(i.tokens))return i;let a=e.revalidateUser?await p(i):i.user;if(!a)return f(i);if(!d(i.tokens))return i;let o=await e.onRevalidate({session:i,accessToken:i.tokens.accessToken,user:a});if(o===null)return f(i);let s={data:o,lastValidatedAt:e.now()};return a!==i.user&&(s.user=a),t.update(i.id,s)}function d(t){return t.accessTokenExpiresAt-e.now()>n.requestTimeoutMs}async function f(n){return n.tokens.accessTokenExpiresAt<=e.now()?n:(await t.delete(n.id),null)}async function p(t){try{return await T(M(e),t.tokens.accessToken)}catch(n){return _(n)?null:(b(e,`revalidate`,n),t.user)}}async function m(e){await t.delete(e.id)}async function h(){if(!t.sweep)return 0;let r=e.now();return t.sweep({createdBefore:r-n.absoluteMaxAgeMs,validatedBefore:r-n.idleMaxAgeMs})}return{load:o,start:s,ensureFreshTokens:c,revalidate:u,revalidationDue:a,end:m,sweep:h}}function W(){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);return!r||n!==void 0&&r.refreshLeaseUntil!==n?!1:(e.delete(t),!0)},async sweep(t){let n=0;for(let[r,i]of e)(i.createdAt<t.createdBefore||i.lastValidatedAt<t.validatedBefore)&&(e.delete(r),n+=1);return n}}}function G(e){let t=S(e),n=U(t),r=V(t,n),i=R(t,n),a=I(t,n);function o(e){return{session:f(e,t.cookieName),cache:f(e,u(t.cookieName))}}async function c(e){return await s(t,e.cache,e.session,t.now())??n.load(e.session)}async function l(e){return c(o(e))}async function d(e){let r=await s(t,e.cache,e.session,t.now());if(r&&r.tokens.accessTokenExpiresAt>t.now())return r.tokens.accessToken;let i=await n.load(e.session);return i?(await n.ensureFreshTokens(i))?.tokens.accessToken??null:null}async function p(e){return d(o(e))}async function m(e,r){let i=await n.load(e.session);return i?t.store.update(i.id,{data:r(i.data)}):null}function h(){return n.sweep()}return{cookieName:t.cookieName,handlers:r,guard:i,resolveSession:a,sessionFromCookies:c,sessionFromRequest:l,accessTokenFromCookies:d,accessTokenFromRequest:p,updateSessionData:m,sweepSessions:h}}export{C as AccountsRequestError,y as DEFAULT_LIFETIMES,x as OAuthTokenError,v as SessionDecodeError,N as accountsEndpoint,u as cacheCookieBase,G as createAccountsAuth,W as createMemorySessionStore,T as fetchUserInfo,r as forwardCookies,_ as isAccessDenied,o as requestOrigin,a as sanitizeRedirectPath};
1
+ import{_ as e,a as t,c as n,d as r,f as i,g as a,h as o,i as s,l as c,m as l,n as u,o as d,p as f,r as p,t as m,u as h,v as g}from"./cache-m-qvewq5.js";import{a as _,i as v,n as y,o as b,r as x,s as S,t as C}from"./types-B_7rFOLg.js";import{a as w,c as T,h as E,i as D,l as O,o as k,p as A,r as j,s as M,t as N,u as P}from"./oidc-0pw9wXd4.js";function F(e,t){return[...d(e.cookieName,t),...m(e,t)]}function I(e,t){return async function(n){let r=o(n),i=f(n,e.cookieName),a=f(n,u(e.cookieName)),c=await s(e,a,i,e.now());if(c)return{session:c,cookies:[]};let l={session:null,cookies:i!==null||a!==null?F(e,r):[]},d=await t.load(i);if(!d)return l;let{deferRevalidation:m}=e;if(m&&t.revalidationDue(d)&&L(e,m,t,d)){let t=await p(e,d,r,e.now());return{session:d,cookies:t?[t]:[]}}let h=d;try{let e=await t.revalidate(d);if(!e)return l;h=e}catch(t){b(e,`revalidate`,t)}let g=await p(e,h,r,e.now());return{session:h,cookies:g?[g]:[]}}}function L(e,t,n,r){try{return t(async()=>{try{await n.revalidate(r)}catch(t){b(e,`revalidate`,t)}}),!0}catch(t){return b(e,`revalidate`,t),!1}}function R(e,t){let n=I(e,t);return async function(t,i={}){let a=new URL(t.url);if([e.paths.login,e.paths.callback,e.paths.logout,e.paths.logoutComplete,e.paths.error,...i.publicPaths??[]].some(e=>a.pathname.startsWith(e)))return{kind:`ok`,session:null};let{session:o,cookies:s}=await n(t);return o?s.length>0?{kind:`ok`,session:o,cookies:s}:{kind:`ok`,session:o}:r(t,i,s)};function r(e,t,n){let r=n.length>0,a=new URL(e.url),o=(t.apiPaths??[`/api`,`/trpc`]).some(e=>a.pathname.startsWith(e))?Response.json({error:`Unauthorized`},{status:401}):l(i(e,t,r));for(let e of n)o.headers.append(`set-cookie`,e);return{kind:`response`,response:o}}function i(t,n,r){let i=new URL(t.url),a=new URL(e.paths.login,o(t));return a.searchParams.set(`redirect`,n.redirectPath?.(t)??`${i.pathname}${i.search}`),r&&a.searchParams.set(`silent`,`1`),a}}const z=/^[A-Za-z0-9_-]{1,128}$/,B=new Set([`login_required`,`consent_required`,`interaction_required`,`account_selection_required`]);function V(r,s){function u(e,t){let n=new URL(r.paths.login,e);return n.searchParams.set(`redirect`,t),n}function d(e,t,n){let i=new URL(r.paths.error,e);return i.searchParams.set(`reason`,t),n&&i.searchParams.set(`description`,n),i}function _(t,n){let a=h(r.cookieName,``),o=[...i(t.headers.get(`cookie`)).keys()].filter(e=>e.replace(/^__Secure-/,``).startsWith(a)),s=o.length-4;for(let t of o.slice(0,Math.max(0,s)))n.headers.append(`set-cookie`,e(t,``,t.startsWith(`__Secure-`),0))}async function v(e){try{let t=await s.load(e);t&&await s.end(t)}catch(e){b(r,`session_store`,e)}}async function y(e){let t=o(e),n=new URL(e.url).searchParams,i=a(n.get(`redirect`),t),s=n.get(`silent`)===`1`,{url:u,state:d,verifier:f}=await D(r,{origin:t,silent:s}),p=l(u);return _(e,p),g(p.headers,h(r.cookieName,d),c({verifier:f,redirectPath:i,silent:s}),t,r.lifetimes.flowMaxAgeMs),p}async function S(e){let i=o(e),c=new URL(e.url).searchParams,_=c.get(`state`),y=_&&z.test(_)?h(r.cookieName,_):null,S=y?n(f(e,y)):null,C=e=>(y&&t(e.headers,y,i),e);if(!S)return C(l(d(i,`invalid_state`,null)));let w=a(S.redirectPath,i),D=c.get(`iss`);if(D!==null&&D!==j(r.issuer))return C(l(d(i,`invalid_issuer`,null)));let O=c.get(`error`);if(O)return S.silent&&B.has(O)?C(l(u(i,w))):C(l(d(i,O,c.get(`error_description`))));let A=c.get(`code`);if(!A)return C(l(d(i,`invalid_request`,null)));let N,P,F;try{let e=await k(r,{code:A,verifier:S.verifier,redirectUri:new URL(r.paths.callback,i).toString()});N=E(e,null,r.now()),P=await T(M(r),N.accessToken),F=await r.onSignIn({user:P,accessToken:N.accessToken,redirectPath:w,previous:null})}catch(e){return b(r,`sign_in`,e),e instanceof x?C(l(d(i,e.code,e.description||null))):C(l(d(i,`accounts_unavailable`,null)))}let I=f(e,r.cookieName);if(F===null){let e=l(d(i,`access_denied`,null));I!==null&&(await v(I),t(e.headers,r.cookieName,i));for(let t of m(r,i))e.headers.append(`set-cookie`,t);return C(e)}let L,R;try{({cookieValue:L,session:R}=await s.start({user:P,tokens:N,data:F}))}catch(e){return b(r,`session_store`,e),C(l(d(i,`session_store_error`,null)))}I!==null&&await v(I);let V=l(new URL(w,i));g(V.headers,r.cookieName,L,i,r.lifetimes.absoluteMaxAgeMs);let H=await p(r,R,i,r.now());return H&&V.headers.append(`set-cookie`,H),C(V)}async function C(e){let t=o(e),n=await s.load(f(e,r.cookieName));n&&await s.end(n);let i=n?.tokens.idToken&&r.logout===`global`?w(r,{origin:t,idToken:n.tokens.idToken}):new URL(r.paths.logoutComplete,t).toString(),a=l(i,303);for(let e of F(r,t))a.headers.append(`set-cookie`,e);return a}return{login:y,callback:S,logout:C}}const H=e=>new Promise(t=>setTimeout(t,e));function U(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}function a(t){let r=e.now();return!i(t.tokens,r)&&r-t.lastValidatedAt>=n.revalidateIntervalMs}async function o(n){if(!n)return null;let i=await A(n),a;try{a=await t.read(i)}catch(n){if(!(n instanceof v))throw n;return b(e,`session_store`,n),await t.delete(i),null}return a?r(a,e.now())?(await t.delete(a.id),null):a:null}async function s(n){let r=O(32),i=e.now(),a={id:await A(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 c(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 l(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 P(e,o.tokens.refreshToken,Math.max(n.refreshLeaseMs-1e3,n.refreshLeaseMs/2));return await t.update(o.id,{tokens:E(r,o.tokens,e.now()),refreshLeaseUntil:null},s)??t.read(o.id)}catch(n){if(_(n))return await t.delete(o.id,s)?null:await t.read(o.id)??null;let r=await t.update(o.id,{refreshLeaseUntil:null},s);if(o.tokens.accessTokenExpiresAt>e.now())return b(e,`refresh`,n),r??o;throw n}}async function l(r,a){for(;;){await H(100);let o=await t.read(r);if(!o)return null;let s=e.now();if(!i(o.tokens,s))return o;if(o.refreshLeaseUntil===null||o.refreshLeaseUntil<=s)return c(o);if(s-a>=n.leaseWaitMs){if(o.tokens.accessTokenExpiresAt>s)return o;throw new C(`Timed out waiting for the session refresh lease`,0)}}}async function u(r){let i;try{i=await c(r)}catch(t){b(e,`refresh`,t),i=r}if(!i)return null;if(e.now()-i.lastValidatedAt<n.revalidateIntervalMs||!d(i.tokens))return i;let a=e.revalidateUser?await p(i):i.user;if(!a)return f(i);if(!d(i.tokens))return i;let o=await e.onRevalidate({session:i,accessToken:i.tokens.accessToken,user:a});if(o===null)return f(i);let s={data:o,lastValidatedAt:e.now()};return a!==i.user&&(s.user=a),t.update(i.id,s)}function d(t){return t.accessTokenExpiresAt-e.now()>n.requestTimeoutMs}async function f(n){return n.tokens.accessTokenExpiresAt<=e.now()?n:(await t.delete(n.id),null)}async function p(t){try{return await T(M(e),t.tokens.accessToken)}catch(n){return _(n)?null:(b(e,`revalidate`,n),t.user)}}async function m(e){await t.delete(e.id)}async function h(){if(!t.sweep)return 0;let r=e.now();return t.sweep({createdBefore:r-n.absoluteMaxAgeMs,validatedBefore:r-n.idleMaxAgeMs})}return{load:o,start:s,ensureFreshTokens:c,revalidate:u,revalidationDue:a,end:m,sweep:h}}function W(){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);return!r||n!==void 0&&r.refreshLeaseUntil!==n?!1:(e.delete(t),!0)},async sweep(t){let n=0;for(let[r,i]of e)(i.createdAt<t.createdBefore||i.lastValidatedAt<t.validatedBefore)&&(e.delete(r),n+=1);return n}}}function G(e){let t=S(e),n=U(t),r=V(t,n),i=R(t,n),a=I(t,n);function o(e){return{session:f(e,t.cookieName),cache:f(e,u(t.cookieName))}}async function c(e){return await s(t,e.cache,e.session,t.now())??n.load(e.session)}async function l(e){return c(o(e))}async function d(e){let r=await s(t,e.cache,e.session,t.now());if(r&&r.tokens.accessTokenExpiresAt>t.now())return r.tokens.accessToken;let i=await n.load(e.session);return i?(await n.ensureFreshTokens(i))?.tokens.accessToken??null:null}async function p(e){return d(o(e))}async function m(e,r){let i=await n.load(e.session);return i?t.store.update(i.id,{data:r(i.data)}):null}function h(){return n.sweep()}return{cookieName:t.cookieName,handlers:r,guard:i,resolveSession:a,sessionFromCookies:c,sessionFromRequest:l,accessTokenFromCookies:d,accessTokenFromRequest:p,updateSessionData:m,sweepSessions:h}}export{C as AccountsRequestError,y as DEFAULT_LIFETIMES,x as OAuthTokenError,v as SessionDecodeError,N as accountsEndpoint,u as cacheCookieBase,G as createAccountsAuth,W as createMemorySessionStore,T as fetchUserInfo,r as forwardCookies,_ as isAccessDenied,o as requestOrigin,a as sanitizeRedirectPath};
package/dist/next.js CHANGED
@@ -1 +1 @@
1
- import{d as e,n as t,s as n}from"./cache-DNvwg4aa.js";import{cookies as r}from"next/headers";import{NextResponse as i,connection as a}from"next/server";function o(t,n=[]){e(t.headers,n);let r=i.next({request:{headers:t.headers}});for(let e of n)r.headers.append(`set-cookie`,e);return r}async function s(e){await a();let i=await r(),o=e=>i.get(n(e,!0))?.value||i.get(n(e,!1))?.value||null;return{session:o(e),cache:o(t(e))}}async function c(e){let i=await r(),a=t(e);for(let e of[n(a,!0),n(a,!1)])try{i.delete(e)}catch{}}function l(e){let t=e.cookieName;return{async getSession(){return e.sessionFromCookies(await s(t))},async getAccessToken(){return e.accessTokenFromCookies(await s(t))},async updateSessionData(n){let r=await e.updateSessionData(await s(t),n);return r&&await c(t),r}}}export{o as continueRequest,l as withNextRequestScope};
1
+ import{d as e,n as t,s as n}from"./cache-m-qvewq5.js";import{cookies as r}from"next/headers";import{NextResponse as i,connection as a}from"next/server";function o(t,n=[]){e(t.headers,n);let r=i.next({request:{headers:t.headers}});for(let e of n)r.headers.append(`set-cookie`,e);return r}async function s(e){await a();let i=await r(),o=e=>i.get(n(e,!0))?.value||i.get(n(e,!1))?.value||null;return{session:o(e),cache:o(t(e))}}async function c(e){let i=await r(),a=t(e);for(let e of[n(a,!0),n(a,!1)])try{i.delete(e)}catch{}}function l(e){let t=e.cookieName;return{async getSession(){return e.sessionFromCookies(await s(t))},async getAccessToken(){return e.accessTokenFromCookies(await s(t))},async updateSessionData(n){let r=await e.updateSessionData(await s(t),n);return r&&await c(t),r}}}export{o as continueRequest,l as withNextRequestScope};
@@ -0,0 +1 @@
1
+ import{n as e,r as t,t as n}from"./types-B_7rFOLg.js";function r(e){let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/g,``)}function i(e){return r(crypto.getRandomValues(new Uint8Array(e)))}async function a(e){let t=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(e));return r(new Uint8Array(t))}function o(e,t){return new URL(t,e).toString()}function s(e){return o(e,`/api/auth`)}function c(e){return{issuer:e.issuer,fetch:e.fetch,timeoutMs:e.lifetimes.requestTimeoutMs}}async function l(t,r,i={},a){let s=t.fetch??globalThis.fetch.bind(globalThis),c=t.timeoutMs??e.requestTimeoutMs,l=a===void 0?c:Math.min(c,a-Date.now());if(l<=0)throw new n(`Accounts request deadline passed`,0);return s(o(t.issuer,r),{...i,cache:`no-store`,signal:AbortSignal.timeout(l)})}async function u(e,t){let n=i(24),r=i(32),s=new URL(o(e.issuer,`/api/auth/oauth2/authorize`));return s.searchParams.set(`client_id`,e.clientId),s.searchParams.set(`redirect_uri`,new URL(e.paths.callback,t.origin).toString()),s.searchParams.set(`response_type`,`code`),s.searchParams.set(`scope`,e.scope),s.searchParams.set(`state`,n),s.searchParams.set(`code_challenge`,await a(r)),s.searchParams.set(`code_challenge_method`,`S256`),t.silent&&s.searchParams.set(`prompt`,`none`),{url:s.toString(),state:n,verifier:r}}function d(e,t){let n=new URL(o(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()}function f(e){return{...c(e),clientId:e.clientId,clientSecret:e.clientSecret,audience:e.audience}}async function p(e){let n=await e.text().catch(()=>``),r=`unknown_error`,i=n;try{let e=JSON.parse(n);r=e.error??r,i=e.error_description??i}catch{}return new t(e.status,r,i)}function m(e){return e.code===`invalid_target`||e.code===`invalid_request`&&/resource/i.test(e.description)}async function h(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=await l(e,`/api/auth/oauth2/token`,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:i},n);if(!a.ok){let i=await p(a);if(r&&e.audience&&m(i))return h(e,t,n,!1);throw i}return await a.json()}function g(e,t){return h(f(e),{grant_type:`authorization_code`,code:t.code,code_verifier:t.verifier,redirect_uri:t.redirectUri})}function _(e,t,n){return h(f(e),{grant_type:`refresh_token`,refresh_token:t},n===void 0?void 0:Date.now()+n)}async function v(e,t){let r=await l(e,`/api/auth/oauth2/userinfo`,{headers:{Authorization:`Bearer ${t}`}});if(!r.ok)throw new n(`Failed to load user info: ${r.status}`,r.status);let i=await r.json();return{id:i.sub,email:i.email??``,name:i.name??i.email??i.sub,image:i.picture??null}}function y(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{d as a,v as c,m as d,h as f,y as h,u as i,i as l,p as m,l as n,g as o,a as p,s as r,c as s,o as t,_ as u};
@@ -0,0 +1,51 @@
1
+ import { s as AccountsRequestError } from "./types-Cx223pmJ.js";
2
+ //#region src/verify/index.d.ts
3
+ type AccountsTokenClaims = {
4
+ iss: string;
5
+ sub: string;
6
+ aud: string | string[];
7
+ exp: number;
8
+ iat?: number;
9
+ nbf?: number;
10
+ scope?: string;
11
+ client_id?: string;
12
+ email?: string;
13
+ name?: string;
14
+ picture?: string;
15
+ sid?: string;
16
+ } & Record<string, unknown>;
17
+ type TokenVerifierConfig = {
18
+ issuer: string;
19
+ /** The audience the token must name: the resource for an access token, the client id for an id token. */
20
+ audience: string | string[];
21
+ /** How long a fetched key set is served before it is read again; ten minutes by default. */
22
+ keysMaxAgeMs?: number;
23
+ /** How soon after a read for an unknown key id the next such read may happen; thirty seconds by default. */
24
+ keysRetryMs?: number;
25
+ /** Tolerance on `exp` and `nbf`; thirty seconds by default. */
26
+ clockSkewMs?: number;
27
+ requestTimeoutMs?: number;
28
+ fetch?: typeof fetch;
29
+ now?: () => number;
30
+ };
31
+ /**
32
+ * Verifies a JWT accounts issued, for a server that receives one as a bearer
33
+ * token: the EdDSA signature against the accounts key set, then `iss`, `aud`,
34
+ * `exp`, `nbf` and `sub`. A token that fails any of them answers null; only a
35
+ * key set that cannot be read at all, with nothing cached to fall back on,
36
+ * throws, because that is the verifier's outage rather than the caller's bad
37
+ * token. Keys are cached and re-read once when a token names a key id the
38
+ * cache does not hold, which is how a rotation shows up.
39
+ */
40
+ declare function createTokenVerifier(config: TokenVerifierConfig): {
41
+ /**
42
+ * The claims of a token accounts issued, or null. `scopes` names the
43
+ * scopes the endpoint needs; a token missing any of them is null as well.
44
+ */
45
+ verify(token: string, options?: {
46
+ scopes?: string[];
47
+ }): Promise<AccountsTokenClaims | null>;
48
+ };
49
+ type TokenVerifier = ReturnType<typeof createTokenVerifier>;
50
+ //#endregion
51
+ export { AccountsRequestError, AccountsTokenClaims, TokenVerifier, TokenVerifierConfig, createTokenVerifier };
package/dist/verify.js ADDED
@@ -0,0 +1 @@
1
+ import{t as e}from"./types-B_7rFOLg.js";import{n as t,r as n}from"./oidc-0pw9wXd4.js";function r(e){let t=e.replace(/-/g,`+`).replace(/_/g,`/`),n=atob(t+`=`.repeat((4-t.length%4)%4)),r=new Uint8Array(n.length);for(let e=0;e<n.length;e++)r[e]=n.charCodeAt(e);return r}function i(e){try{let t=JSON.parse(new TextDecoder().decode(r(e)));return typeof t==`object`&&t&&!Array.isArray(t)?t:null}catch{return null}}async function a(e){let t=typeof e==`object`&&e&&Array.isArray(e.keys)?e.keys:null;if(t===null)throw Error(`The key set has no keys array`);let n=new Map;for(let[e,r]of t.entries())if(!(typeof r!=`object`||!r||r.kty!==`OKP`||r.crv!==`Ed25519`||typeof r.x!=`string`))try{let t=await crypto.subtle.importKey(`jwk`,{kty:r.kty,crv:r.crv,x:r.x},{name:`Ed25519`},!1,[`verify`]);n.set(typeof r.kid==`string`?r.kid:`#${e}`,t)}catch{}return n}function o(o){let s=o.now??Date.now,c=n(o.issuer),l=new Set(Array.isArray(o.audience)?o.audience:[o.audience]),u=o.keysMaxAgeMs??6e5,d=o.keysRetryMs??3e4,f=o.clockSkewMs??3e4,p={issuer:o.issuer,fetch:o.fetch,timeoutMs:o.requestTimeoutMs},m=null,h=null;function g(){return h??=(async()=>{try{let n=await t(p,`/api/auth/jwks`);if(!n.ok)throw new e(`Failed to load the accounts key set: ${n.status}`,n.status);let r;try{r=await a(await n.json())}catch(t){throw new e(`Failed to read the accounts key set: ${t instanceof Error?t.message:String(t)}`,n.status)}return m={keys:r,loadedAt:s()},m}finally{h=null}})(),h}async function _(){try{return await g()}catch(e){if(m)return m;throw e}}let v=-1/0;async function y(e){let t=m&&s()-m.loadedAt<u?m:await _();if(e!==null&&!t.keys.has(e)&&s()-v>=d&&(v=s(),t=await _()),e===null)return[...t.keys.values()];let n=t.keys.get(e);return n?[n]:[]}return{async verify(e,t={}){let n=e.split(`.`);if(n.length!==3)return null;let a=i(n[0]),o=i(n[1]);if(!a||!o||a.alg!==`EdDSA`)return null;let u;try{u=r(n[2])}catch{return null}let d=new TextEncoder().encode(`${n[0]}.${n[1]}`),p=!1;for(let e of await y(typeof a.kid==`string`?a.kid:null))if(await crypto.subtle.verify(`Ed25519`,e,u,d)){p=!0;break}if(!p||o.iss!==c||!(Array.isArray(o.aud)?o.aud:typeof o.aud==`string`?[o.aud]:[]).some(e=>typeof e==`string`&&l.has(e)))return null;let m=s()/1e3,h=f/1e3;if(typeof o.exp!=`number`||o.exp+h<=m||typeof o.nbf==`number`&&o.nbf-h>m||typeof o.sub!=`string`||o.sub===``)return null;if(t.scopes?.length){let e=new Set(typeof o.scope==`string`?o.scope.split(` `):[]);if(!t.scopes.every(t=>e.has(t)))return null}return o}}}export{e as AccountsRequestError,o as createTokenVerifier};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aui-auth",
3
- "version": "0.0.7",
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",
3
+ "version": "0.0.8",
4
+ "description": "Sign in through assistant-ui accounts: server side sessions for web apps (OIDC code flow with PKCE, tokens kept in the app's store, single flight refresh), the device grant for CLIs, and token verification for resource servers",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "sideEffects": false,
@@ -21,6 +21,14 @@
21
21
  "types": "./dist/next.d.ts",
22
22
  "default": "./dist/next.js"
23
23
  },
24
+ "./device": {
25
+ "types": "./dist/device.d.ts",
26
+ "default": "./dist/device.js"
27
+ },
28
+ "./verify": {
29
+ "types": "./dist/verify.d.ts",
30
+ "default": "./dist/verify.js"
31
+ },
24
32
  "./database": {
25
33
  "types": "./dist/database/index.d.ts",
26
34
  "default": "./dist/database/index.js"
@@ -1 +0,0 @@
1
- import{n as e,r as t,t as n}from"./types-B_7rFOLg.js";function r(e){let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/g,``)}function i(e){return r(crypto.getRandomValues(new Uint8Array(e)))}async function a(e){let t=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(e));return r(new Uint8Array(t))}function o(e,t){return new URL(t,e).toString()}function s(e){return o(e,`/api/auth`)}function c(e){return{issuer:e.issuer,fetch:e.fetch,timeoutMs:e.lifetimes.requestTimeoutMs}}async function l(t,r,i={},a){let s=t.fetch??globalThis.fetch.bind(globalThis),c=t.timeoutMs??e.requestTimeoutMs,l=a===void 0?c:Math.min(c,a-Date.now());if(l<=0)throw new n(`Accounts request deadline passed`,0);return s(o(t.issuer,r),{...i,cache:`no-store`,signal:AbortSignal.timeout(l)})}async function u(e,t){let n=i(24),r=i(32),s=new URL(o(e.issuer,`/api/auth/oauth2/authorize`));return s.searchParams.set(`client_id`,e.clientId),s.searchParams.set(`redirect_uri`,new URL(e.paths.callback,t.origin).toString()),s.searchParams.set(`response_type`,`code`),s.searchParams.set(`scope`,e.scope),s.searchParams.set(`state`,n),s.searchParams.set(`code_challenge`,await a(r)),s.searchParams.set(`code_challenge_method`,`S256`),t.silent&&s.searchParams.set(`prompt`,`none`),{url:s.toString(),state:n,verifier:r}}function d(e,t){let n=new URL(o(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 f(e,n,r,i=!0){let a=new URLSearchParams({client_id:e.clientId,...n});e.clientSecret&&a.set(`client_secret`,e.clientSecret),e.audience&&i&&a.set(`resource`,e.audience);let o=await l(c(e),`/api/auth/oauth2/token`,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:a},r);if(!o.ok){let a=await o.text().catch(()=>``),s=`unknown_error`,c=a;try{let e=JSON.parse(a);s=e.error??s,c=e.error_description??c}catch{}if(i&&e.audience&&(s===`invalid_target`||s===`invalid_request`&&/resource/i.test(c)))return f(e,n,r,!1);throw new t(o.status,s,c)}return await o.json()}function p(e,t){return f(e,{grant_type:`authorization_code`,code:t.code,code_verifier:t.verifier,redirect_uri:t.redirectUri})}function m(e,t,n){return f(e,{grant_type:`refresh_token`,refresh_token:t},n===void 0?void 0:Date.now()+n)}async function h(e,t){let r=await l(e,`/api/auth/oauth2/userinfo`,{headers:{Authorization:`Bearer ${t}`}});if(!r.ok)throw new n(`Failed to load user info: ${r.status}`,r.status);let i=await r.json();return{id:i.sub,email:i.email??``,name:i.name??i.email??i.sub,image:i.picture??null}}function g(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{d as a,h as c,a as d,g as f,u as i,i as l,l as n,p as o,s as r,c as s,o as t,m as u};