@frank-auth/react
Version:
Flexible and customizable React UI components for Frank Authentication
3 lines (2 loc) • 11.2 kB
JavaScript
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const T=require("@frank-auth/sdk"),p=require("next/server"),b={apiUrl:"http://localhost:8990",sessionCookieName:"frank_sid",storageKeyPrefix:"frank_auth_",publicPaths:[],privatePaths:[],authPaths:["/sign-in","/sign-up","/forgot-password","/verify-email","/reset-password"],skipApiCallOnNetworkError:!1,maxRetries:2,apiTimeout:5e3,fallbackToLocalTokens:!0,offlineMode:!1,allPathsPrivate:!0,signInPath:"/sign-in",signUpPath:"/sign-up",afterSignInPath:"/dashboard",afterSignUpPath:"/dashboard",afterSignOutPath:"/",orgSelectionPath:"/select-organization",debug:!1,enableOrgRouting:!1,ignorePaths:["/api","/_next","/favicon.ico","/images","/static","/_vercel"],cookieOptions:{secure:process.env.NODE_ENV==="production",httpOnly:!0,sameSite:"lax",maxAge:60*60*24*7}};function A(s,t){return t.some(e=>{if(e===s)return!0;if(e.endsWith("*")){const r=e.slice(0,-1);return s.startsWith(r)}return e.startsWith("/")&&e.endsWith("/")?new RegExp(e.slice(1,-1)).test(s):!1})}function I(s,t,e){const r=s.cookies.getAll(),k={cookies:{...Object.fromEntries(r.map(a=>[a.name,a.value])),get:a=>s.cookies.get(a),getAll:()=>s.cookies.getAll()}},f={setHeader:(a,o)=>{if(a==="Set-Cookie"){const u=Array.isArray(o)?o:[o];for(const n of u){const[h,...l]=n.split(";"),[d,i]=h.split("=");if(d&&i){const m={httpOnly:e.cookieOptions.httpOnly,secure:e.cookieOptions.secure,sameSite:e.cookieOptions.sameSite,maxAge:e.cookieOptions.maxAge,path:"/"};for(const x of l){const[g,P]=x.trim().split("=");switch(g.toLowerCase()){case"max-age":m.maxAge=Number.parseInt(P,10);break;case"expires":m.expires=new Date(P);break;case"path":m.path=P;break;case"domain":m.domain=P;break;case"secure":m.secure=!0;break;case"httponly":m.httpOnly=!0;break;case"samesite":m.sameSite=P;break}}t.cookies.set(d.trim(),i.trim(),m)}}}else t.headers.set(a,Array.isArray(o)?o.join(", "):o)},getHeader:a=>t.headers.get(a)};return new T.NextJSCookieContext(k,f)}function E(s,t,e){I(t,e,s);const r=T.createHybridAuthStorage(s.storageKeyPrefix,{req:t,res:{setHeader:(f,a)=>{if(f==="Set-Cookie"){const o=Array.isArray(a)?a:[a];for(const u of o){const[n,...h]=u.split(";"),[l,d]=n.split("=");if(l&&d){const i={httpOnly:s.cookieOptions.httpOnly,secure:s.cookieOptions.secure,sameSite:s.cookieOptions.sameSite,maxAge:s.cookieOptions.maxAge};for(const m of h){const[x,g]=m.trim().split("=");switch(x.toLowerCase()){case"max-age":i.maxAge=Number.parseInt(g,10);break;case"expires":i.expires=new Date(g);break;case"path":i.path=g;break;case"domain":i.domain=g;break;case"secure":i.secure=!0;break;case"httponly":i.httpOnly=!0;break;case"samesite":i.sameSite=g;break}}e.cookies.set(l.trim(),d.trim(),i)}}}else e.headers.set(f,Array.isArray(a)?a.join(", "):a)},getHeader:f=>e.headers.get(f)}});return c(s,"Storage tokens:",{accessToken:r.getAccessToken()?"[PRESENT]":"[MISSING]",refreshToken:r.getRefreshToken()?"[PRESENT]":"[MISSING]",sessionId:r.getSessionId()?"[PRESENT]":"[MISSING]",remoteSessionCookie:t.cookies.get("frank_sid")?.value,storageKeyPrefix:s.storageKeyPrefix,userType:s.userType,projectId:s.projectId,secretKey:s.secretKey,apiUrl:s.apiUrl}),new T.AuthSDK({apiUrl:s.apiUrl,publishableKey:s.publishableKey,sessionCookieName:s.sessionCookieName,storageKeyPrefix:s.storageKeyPrefix,userType:s.userType,projectId:s.projectId,secretKey:s.secretKey,storage:r,debug:s.debug,debugConfig:{logLevel:"debug"}})}async function y(s,t,e){try{c(e,"Validating authentication using AuthSDK");const r=!!t.authStorage.getAccessToken(),k=!!t.authStorage.getRefreshToken(),a=!!s.cookies.get(e.sessionCookieName)?.value;if(c(e,"Authentication state:",{hasAccessToken:r,hasRefreshToken:k,hasSessionCookie:a,sessionCookieName:e.sessionCookieName}),!r&&!k&&!a)return c(e,"No tokens or session cookies found, skipping API call"),{isAuthenticated:!1,user:null,session:null,organizationId:null,error:null,tokenInfo:{accessTokenExpired:!0,refreshTokenExpired:!0,canRefresh:!1}};const o=t.getTokenExpirationInfo();if(c(e,"Token expiration info:",{accessToken:{isExpired:o.accessToken.isExpired,expiresIn:o.accessToken.expiresIn},refreshToken:{isExpired:o.refreshToken.isExpired,expiresIn:o.refreshToken.expiresIn}}),e.skipApiCallOnNetworkError&&process.env.NODE_ENV==="development"&&(c(e,"Skipping API call due to development mode network configuration"),r&&!o.accessToken.isExpired||a))return{isAuthenticated:!0,user:null,session:null,organizationId:e.projectId||null,error:null,tokenInfo:{accessTokenExpired:o.accessToken.isExpired,refreshTokenExpired:o.refreshToken.isExpired,canRefresh:!o.refreshToken.isExpired}};const u=async()=>{const d=new AbortController,i=setTimeout(()=>d.abort(),5e3),m=s.cookies.getAll().map(x=>`${x.name}=${x.value}`).join("; ");try{const x=await t.getAuthStatus({credentials:"include",signal:d.signal,headers:{"User-Agent":"FrankAuth-Middleware/1.0",Accept:"application/json","Content-Type":"application/json","X-Forwarded-For":s.headers.get("x-forwarded-for")||"","X-Real-IP":s.headers.get("x-real-ip")||"",Cookie:m},cache:"no-cache",keepalive:!1});return clearTimeout(i),x}catch(x){throw clearTimeout(i),x}};let n,h=null;const l=e.maxRetries||2;for(let d=1;d<=l;d++)try{c(e,`Auth status attempt ${d}/${l}`),n=await u();break}catch(i){if(h=i,c(e,`Auth status attempt ${d} failed:`,{name:i.name,message:i.message,code:i.code}),d===l){if(e.fallbackToLocalTokens&&(r&&!o.accessToken.isExpired||a))return c(e,"API failed but local token/session is valid, trusting local state"),{isAuthenticated:!0,user:null,session:null,organizationId:e.projectId||null,error:i,tokenInfo:{accessTokenExpired:o.accessToken.isExpired,refreshTokenExpired:o.refreshToken.isExpired,canRefresh:!o.refreshToken.isExpired}};throw i}if(!S(i))throw i;const m=Math.min(1e3*Math.pow(2,d-1),5e3),x=Math.random()*.1*m;await new Promise(g=>setTimeout(g,m+x))}return c(e,"Auth status received:",{isAuthenticated:n.isAuthenticated,hasUser:!!n.user,organizationId:n.organizationId}),{isAuthenticated:n.isAuthenticated,user:n.user||null,session:n.session||null,organizationId:n.organizationId||null,error:null,tokenInfo:{accessTokenExpired:o.accessToken.isExpired,refreshTokenExpired:o.refreshToken.isExpired,canRefresh:!o.refreshToken.isExpired}}}catch(r){c(e,"Authentication validation error:",{name:r.name,message:r.message,code:r.code});const k=t.getTokenExpirationInfo();return{isAuthenticated:!1,user:null,session:null,organizationId:null,error:r,tokenInfo:{accessTokenExpired:k.accessToken.isExpired,refreshTokenExpired:k.refreshToken.isExpired,canRefresh:!k.refreshToken.isExpired&&k.refreshToken.isValid}}}}function S(s){const t=["NETWORK_ERROR","ECONNREFUSED","ENOTFOUND","ECONNRESET","ETIMEDOUT","AbortError"];return s?.code&&t.includes(s.code)||s?.name==="FrankAuthNetworkError"||s?.message?.includes("fetch failed")||s?.message?.includes("network")||s?.name==="AbortError"}function w(s,t){if(!t.enableOrgRouting)return null;const e=s.nextUrl.hostname;if(t.customDomain&&e===t.customDomain)return s.nextUrl.searchParams.get("org")||null;const r=e.split(".");return r.length>2?r[0]:null}function c(s,t,e){s.debug&&console.log(`[FrankAuth Middleware] ${t}`,e||"")}async function N(s,t){const e=s.nextUrl.pathname;if(c(t,`Processing request: ${e}`),A(e,t.ignorePaths))return c(t,`Ignoring path: ${e}`),p.NextResponse.next();const r=p.NextResponse.next();if(t.hooks?.beforeAuth){const l=await t.hooks.beforeAuth(s);if(l instanceof p.NextResponse)return l;l instanceof p.NextRequest&&(s=l)}const k=E(t,s,r),f=A(e,t.publicPaths),a=A(e,t.authPaths);let o;t.allPathsPrivate?o=!f&&!a:o=A(e,t.privatePaths),c(t,"Path analysis:",{isPublicPath:f,isPrivatePath:o,isAuthPath:a,allPathsPrivate:t.allPathsPrivate});const u=await y(s,k,t);c(t,"Authentication result:",{isAuthenticated:u.isAuthenticated,hasUser:!!u.user,organizationId:u.organizationId,tokenInfo:u.tokenInfo});const h=await O({req:s,config:t,auth:u,path:e,isPublicPath:f,isPrivatePath:o,isAuthPath:a,response:r});if(t.hooks?.afterAuth){const l=await t.hooks.afterAuth(s,h,u);if(l instanceof p.NextResponse)return l}return h}async function O(s){const{req:t,config:e,auth:r,path:k,isPublicPath:f,isPrivatePath:a,isAuthPath:o,response:u}=s;try{if(r.isAuthenticated&&r.user){if(c(e,"User is authenticated"),e.hooks?.onAuthenticated&&r.session){const n=await e.hooks.onAuthenticated(t,r.user,r.session);if(n instanceof p.NextResponse)return n}if(o){const n=t.nextUrl.searchParams.get("redirect_url")||e.afterSignInPath;c(e,`Redirecting authenticated user from auth path to: ${n}`);const h=p.NextResponse.redirect(new URL(n,t.url));return R(u,h),h}if(e.enableOrgRouting&&!r.organizationId&&k!==e.orgSelectionPath){if(c(e,"Organization required but not selected"),e.hooks?.onOrganizationRequired){const h=await e.hooks.onOrganizationRequired(t,r.user);if(h instanceof p.NextResponse)return h}const n=p.NextResponse.redirect(new URL(e.orgSelectionPath,t.url));return R(u,n),n}return u}if(c(e,"User is not authenticated"),e.hooks?.onUnauthenticated){const n=await e.hooks.onUnauthenticated(t);if(n instanceof p.NextResponse)return n}if(f||o)return c(e,"Allowing access to public/auth path"),u;if(a){const n=new URL(e.signInPath,t.url);n.searchParams.set("redirect_url",t.nextUrl.pathname+t.nextUrl.search),c(e,`Redirecting to sign in: ${n.toString()}`);const h=p.NextResponse.redirect(n);return R(u,h),h}return u}catch(n){if(c(e,"Error in authentication handling:",n),e.hooks?.onError){const d=await e.hooks.onError(t,n);if(d instanceof p.NextResponse)return d}const h=new URL(e.signInPath,t.url);h.searchParams.set("error","auth_error");const l=p.NextResponse.redirect(h);return R(u,l),l}}function R(s,t){try{const e=s.headers.getSetCookie();if(e.length>0)for(const r of e)t.headers.append("Set-Cookie",r);for(const r of s.cookies.getAll())r.name&&r.value&&t.cookies.set(r.name,r.value,{domain:r.domain,expires:r.expires,httpOnly:r.httpOnly,maxAge:r.maxAge,path:r.path||"/",secure:r.secure,sameSite:r.sameSite})}catch(e){console.error("Error copying response cookies:",e)}}function C(s){const t={...b,...s};if(!t.publishableKey)throw new Error("publishableKey is required for Frank Auth middleware");return t.storageKeyPrefix||(t.storageKeyPrefix="frank_auth"),c(t,"Frank Auth middleware initialized with config:",{publicPaths:t.publicPaths,privatePaths:t.privatePaths,authPaths:t.authPaths,allPathsPrivate:t.allPathsPrivate,signInPath:t.signInPath,enableOrgRouting:t.enableOrgRouting,storageKeyPrefix:t.storageKeyPrefix}),async function(r){return N(r,t)}}function U(s){return function(e){return s.custom?s.custom(e):s.exclude&&A(e,s.exclude)?!1:!!(s.include&&A(e,s.include))}}async function v(s,t,e){try{const r=p.NextResponse.next(),k=E(e,s,r),f=s.cookies.getAll().map(o=>`${o.name}=${o.value}`).join("; ");return(await k.getAuthStatus({headers:{Cookie:f}})).isAuthenticated}catch{return!1}}function K(s,t){return w(s,t)}function z(s,t){const e=p.NextResponse.next();return E(t,s,e)}async function D(s,t){const e=p.NextResponse.next(),r=E(t,s,e);return y(s,r,t)}exports.checkAuthStatus=D;exports.checkPermission=v;exports.createFrankAuthMiddleware=C;exports.createMatcher=U;exports.getAuthSDKFromRequest=z;exports.getOrganizationFromRequest=K;
//# sourceMappingURL=index.cjs.map