@imtbl/auth-next-server 2.12.5-alpha.13 → 2.12.5-alpha.14
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/browser/index.js +7 -0
- package/dist/node/index.cjs +20 -431
- package/dist/node/index.js +5 -388
- package/package.json +9 -7
- /package/dist/{node → types}/config.d.ts +0 -0
- /package/dist/{node → types}/constants.d.ts +0 -0
- /package/dist/{node → types}/index.d.ts +0 -0
- /package/dist/{node → types}/refresh.d.ts +0 -0
- /package/dist/{node → types}/types.d.ts +0 -0
- /package/dist/{node → types}/utils/pathMatch.d.ts +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import A from 'next-auth';
|
|
2
|
+
import { NextResponse } from 'next/server';
|
|
3
|
+
import x from 'next-auth/providers/credentials';
|
|
4
|
+
|
|
5
|
+
var m="https://auth.immutable.com";var k="immutable";function E(n,t=60){return typeof n!="number"||Number.isNaN(n)?!0:Date.now()>=n-t*1e3}var y=x.default||x;async function w(n,t){try{let r=await fetch(`${t}/userinfo`,{method:"GET",headers:{Authorization:`Bearer ${n}`}});return r.ok?await r.json():(console.error("[auth-next-server] Token validation failed:",r.status,r.statusText),null)}catch(r){return console.error("[auth-next-server] Token validation error:",r),null}}function d(n){let t=n.authenticationDomain||m;return {providers:[y({id:k,name:"Immutable",credentials:{tokens:{label:"Tokens",type:"text"}},async authorize(r){if(!r?.tokens||typeof r.tokens!="string")return null;let e;try{e=JSON.parse(r.tokens);}catch(a){return console.error("[auth-next-server] Failed to parse token data:",a),null}if(!e.accessToken||typeof e.accessToken!="string"||!e.profile||typeof e.profile!="object"||!e.profile.sub||typeof e.profile.sub!="string"||typeof e.accessTokenExpires!="number"||Number.isNaN(e.accessTokenExpires))return console.error("[auth-next-server] Invalid token data structure - missing required fields"),null;let o=await w(e.accessToken,t);return o?o.sub!==e.profile.sub?(console.error("[auth-next-server] User ID mismatch - userinfo sub:",o.sub,"provided sub:",e.profile.sub),null):{id:o.sub,sub:o.sub,email:o.email??e.profile.email,nickname:o.nickname??e.profile.nickname,accessToken:e.accessToken,refreshToken:e.refreshToken,idToken:e.idToken,accessTokenExpires:e.accessTokenExpires,zkEvm:e.zkEvm}:(console.error("[auth-next-server] Token validation failed - rejecting authentication"),null)}})],callbacks:{async jwt({token:r,user:e,trigger:o,session:a}){if(e)return {...r,sub:e.sub,email:e.email,nickname:e.nickname,accessToken:e.accessToken,refreshToken:e.refreshToken,idToken:e.idToken,accessTokenExpires:e.accessTokenExpires,zkEvm:e.zkEvm};if(o==="update"&&a){let s=a;return {...r,...s.accessToken?{accessToken:s.accessToken}:{},...s.refreshToken?{refreshToken:s.refreshToken}:{},...s.idToken?{idToken:s.idToken}:{},...s.accessTokenExpires?{accessTokenExpires:s.accessTokenExpires}:{},...s.zkEvm?{zkEvm:s.zkEvm}:{},error:void 0}}return E(r.accessTokenExpires)?{...r,error:"TokenExpired"}:r},async session({session:r,token:e}){return {...r,user:{...r.user,sub:e.sub,email:e.email,nickname:e.nickname},accessToken:e.accessToken,refreshToken:e.refreshToken,idToken:e.idToken,accessTokenExpires:e.accessTokenExpires,zkEvm:e.zkEvm,...e.error&&{error:e.error}}}},session:{strategy:"jwt",maxAge:31536e3}}}var I=d;function T(n,t){if(n===t)return !0;let r=t.endsWith("/")?t:`${t}/`;return n.startsWith(r)}var g=A.default||A;function Q(n,t){let r=d(n);if(!t)return g(r);let{callbacks:e,...o}=t,a={...r.callbacks};if(e){if(e.jwt){let c=r.callbacks?.jwt,l=e.jwt;a.jwt=async i=>{let u=c?await c(i):i.token;return l({...i,token:u})};}if(e.session){let c=r.callbacks?.session,l=e.session;a.session=async i=>{let u=c?await c(i):i.session;return l({...i,session:u})};}e.signIn&&(a.signIn=e.signIn),e.redirect&&(a.redirect=e.redirect),e.authorized&&(a.authorized=e.authorized);}let s={...r,...o,callbacks:a};return g(s)}async function D(n){let t=await n();return t?t.error==="TokenExpired"?{session:null,ssr:!1}:t.error?{session:null,ssr:!1,authError:t.error}:{session:t,ssr:!0}:{session:null,ssr:!1}}async function F(n,t){let r=await n();if(!r)return {session:null,ssr:!1,data:null};if(r.error==="TokenExpired")return {session:null,ssr:!1,data:null};if(r.error)return {session:null,ssr:!1,data:null,authError:r.error};try{let e=await t(r.accessToken);return {session:r,ssr:!0,data:e}}catch(e){let o=e instanceof Error?e.message:String(e);return {session:r,ssr:!0,data:null,fetchError:o}}}async function U(n){let t=await n();return t?t.error?t.error==="TokenExpired"?{status:"token_expired",session:t}:{status:"error",session:t,error:t.error}:{status:"authenticated",session:t}:{status:"unauthenticated",session:null}}function _(n,t){return async function(e){let o=await F(n,e);o.authError&&t(o.authError);let{authError:a,...s}=o;return s}}function S(n,t){return async function(){let e=await D(n);e.authError&&t(e.authError);let{authError:o,...a}=e;return a}}function q(n,t){return {getAuthProps:S(n,t),getData:_(n,t)}}async function ee(n,t,r={}){let e=await U(n);switch(e.status){case"authenticated":return t(e.session);case"token_expired":return r.onTokenExpired!==void 0?typeof r.onTokenExpired=="function"?r.onTokenExpired():r.onTokenExpired:t(e.session);case"unauthenticated":if(r.onUnauthenticated!==void 0)return typeof r.onUnauthenticated=="function"?r.onUnauthenticated():r.onUnauthenticated;throw new Error("Unauthorized: No active session");case"error":if(r.onError!==void 0)return typeof r.onError=="function"?r.onError(e.error):r.onError;throw new Error(`Unauthorized: ${e.error}`);default:throw new Error("Unknown auth state")}}function re(n,t={}){let{loginUrl:r="/login",protectedPaths:e,publicPaths:o}=t;return async function(s){let{pathname:c}=s.nextUrl;if(o&&o.some(u=>typeof u=="string"?T(c,u):u.test(c)))return NextResponse.next();if(e&&!e.some(u=>typeof u=="string"?T(c,u):u.test(c)))return NextResponse.next();let l=await n();if(!l){let i=new URL(r,s.url),u=s.nextUrl.search?`${c}${s.nextUrl.search}`:c;return i.searchParams.set("returnTo",u),NextResponse.redirect(i)}if(l.error&&l.error!=="TokenExpired"){let i=new URL(r,s.url),u=s.nextUrl.search?`${c}${s.nextUrl.search}`:c;return i.searchParams.set("returnTo",u),i.searchParams.set("error",l.error),NextResponse.redirect(i)}return NextResponse.next()}}function te(n,t){return async(...r)=>{let e=await n();if(!e)throw new Error("Unauthorized: No active session");if(e.error&&e.error!=="TokenExpired")throw new Error(`Unauthorized: ${e.error}`);return t(e,...r)}}
|
|
6
|
+
|
|
7
|
+
export { d as createAuthConfig, re as createAuthMiddleware, I as createAuthOptions, Q as createImmutableAuth, S as createProtectedAuthProps, _ as createProtectedDataFetcher, q as createProtectedFetchers, D as getAuthProps, F as getAuthenticatedData, U as getValidSession, te as withAuth, ee as withServerAuth };
|
package/dist/node/index.cjs
CHANGED
|
@@ -1,436 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
1
|
+
'use strict';
|
|
29
2
|
|
|
30
|
-
|
|
31
|
-
var
|
|
32
|
-
|
|
33
|
-
createAuthConfig: () => createAuthConfig,
|
|
34
|
-
createAuthMiddleware: () => createAuthMiddleware,
|
|
35
|
-
createAuthOptions: () => createAuthOptions,
|
|
36
|
-
createImmutableAuth: () => createImmutableAuth,
|
|
37
|
-
createProtectedAuthProps: () => createProtectedAuthProps,
|
|
38
|
-
createProtectedDataFetcher: () => createProtectedDataFetcher,
|
|
39
|
-
createProtectedFetchers: () => createProtectedFetchers,
|
|
40
|
-
getAuthProps: () => getAuthProps,
|
|
41
|
-
getAuthenticatedData: () => getAuthenticatedData,
|
|
42
|
-
getValidSession: () => getValidSession,
|
|
43
|
-
withAuth: () => withAuth,
|
|
44
|
-
withServerAuth: () => withServerAuth
|
|
45
|
-
});
|
|
46
|
-
module.exports = __toCommonJS(src_exports);
|
|
47
|
-
var import_next_auth = __toESM(require("next-auth"), 1);
|
|
48
|
-
var import_server = require("next/server");
|
|
3
|
+
var E = require('next-auth');
|
|
4
|
+
var server = require('next/server');
|
|
5
|
+
var k = require('next-auth/providers/credentials');
|
|
49
6
|
|
|
50
|
-
|
|
51
|
-
var import_credentials = __toESM(require("next-auth/providers/credentials"), 1);
|
|
7
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
52
8
|
|
|
53
|
-
|
|
54
|
-
var
|
|
55
|
-
var IMMUTABLE_PROVIDER_ID = "immutable";
|
|
56
|
-
var DEFAULT_TOKEN_EXPIRY_SECONDS = 900;
|
|
57
|
-
var DEFAULT_TOKEN_EXPIRY_MS = DEFAULT_TOKEN_EXPIRY_SECONDS * 1e3;
|
|
58
|
-
var TOKEN_EXPIRY_BUFFER_SECONDS = 60;
|
|
59
|
-
var DEFAULT_SESSION_MAX_AGE_SECONDS = 365 * 24 * 60 * 60;
|
|
9
|
+
var E__default = /*#__PURE__*/_interopDefault(E);
|
|
10
|
+
var k__default = /*#__PURE__*/_interopDefault(k);
|
|
60
11
|
|
|
61
|
-
|
|
62
|
-
function isTokenExpired(accessTokenExpires, bufferSeconds = TOKEN_EXPIRY_BUFFER_SECONDS) {
|
|
63
|
-
if (typeof accessTokenExpires !== "number" || Number.isNaN(accessTokenExpires)) {
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
return Date.now() >= accessTokenExpires - bufferSeconds * 1e3;
|
|
67
|
-
}
|
|
12
|
+
var d="https://auth.immutable.com";var T="immutable";function m(n,t=60){return typeof n!="number"||Number.isNaN(n)?!0:Date.now()>=n-t*1e3}var P=k__default.default.default||k__default.default;async function b(n,t){try{let r=await fetch(`${t}/userinfo`,{method:"GET",headers:{Authorization:`Bearer ${n}`}});return r.ok?await r.json():(console.error("[auth-next-server] Token validation failed:",r.status,r.statusText),null)}catch(r){return console.error("[auth-next-server] Token validation error:",r),null}}function f(n){let t=n.authenticationDomain||d;return {providers:[P({id:T,name:"Immutable",credentials:{tokens:{label:"Tokens",type:"text"}},async authorize(r){if(!r?.tokens||typeof r.tokens!="string")return null;let e;try{e=JSON.parse(r.tokens);}catch(a){return console.error("[auth-next-server] Failed to parse token data:",a),null}if(!e.accessToken||typeof e.accessToken!="string"||!e.profile||typeof e.profile!="object"||!e.profile.sub||typeof e.profile.sub!="string"||typeof e.accessTokenExpires!="number"||Number.isNaN(e.accessTokenExpires))return console.error("[auth-next-server] Invalid token data structure - missing required fields"),null;let o=await b(e.accessToken,t);return o?o.sub!==e.profile.sub?(console.error("[auth-next-server] User ID mismatch - userinfo sub:",o.sub,"provided sub:",e.profile.sub),null):{id:o.sub,sub:o.sub,email:o.email??e.profile.email,nickname:o.nickname??e.profile.nickname,accessToken:e.accessToken,refreshToken:e.refreshToken,idToken:e.idToken,accessTokenExpires:e.accessTokenExpires,zkEvm:e.zkEvm}:(console.error("[auth-next-server] Token validation failed - rejecting authentication"),null)}})],callbacks:{async jwt({token:r,user:e,trigger:o,session:a}){if(e)return {...r,sub:e.sub,email:e.email,nickname:e.nickname,accessToken:e.accessToken,refreshToken:e.refreshToken,idToken:e.idToken,accessTokenExpires:e.accessTokenExpires,zkEvm:e.zkEvm};if(o==="update"&&a){let s=a;return {...r,...s.accessToken?{accessToken:s.accessToken}:{},...s.refreshToken?{refreshToken:s.refreshToken}:{},...s.idToken?{idToken:s.idToken}:{},...s.accessTokenExpires?{accessTokenExpires:s.accessTokenExpires}:{},...s.zkEvm?{zkEvm:s.zkEvm}:{},error:void 0}}return m(r.accessTokenExpires)?{...r,error:"TokenExpired"}:r},async session({session:r,token:e}){return {...r,user:{...r.user,sub:e.sub,email:e.email,nickname:e.nickname},accessToken:e.accessToken,refreshToken:e.refreshToken,idToken:e.idToken,accessTokenExpires:e.accessTokenExpires,zkEvm:e.zkEvm,...e.error&&{error:e.error}}}},session:{strategy:"jwt",maxAge:31536e3}}}var y=f;function p(n,t){if(n===t)return !0;let r=t.endsWith("/")?t:`${t}/`;return n.startsWith(r)}var x=E__default.default.default||E__default.default;function $(n,t){let r=f(n);if(!t)return x(r);let{callbacks:e,...o}=t,a={...r.callbacks};if(e){if(e.jwt){let c=r.callbacks?.jwt,l=e.jwt;a.jwt=async i=>{let u=c?await c(i):i.token;return l({...i,token:u})};}if(e.session){let c=r.callbacks?.session,l=e.session;a.session=async i=>{let u=c?await c(i):i.session;return l({...i,session:u})};}e.signIn&&(a.signIn=e.signIn),e.redirect&&(a.redirect=e.redirect),e.authorized&&(a.authorized=e.authorized);}let s={...r,...o,callbacks:a};return x(s)}async function w(n){let t=await n();return t?t.error==="TokenExpired"?{session:null,ssr:!1}:t.error?{session:null,ssr:!1,authError:t.error}:{session:t,ssr:!0}:{session:null,ssr:!1}}async function I(n,t){let r=await n();if(!r)return {session:null,ssr:!1,data:null};if(r.error==="TokenExpired")return {session:null,ssr:!1,data:null};if(r.error)return {session:null,ssr:!1,data:null,authError:r.error};try{let e=await t(r.accessToken);return {session:r,ssr:!0,data:e}}catch(e){let o=e instanceof Error?e.message:String(e);return {session:r,ssr:!0,data:null,fetchError:o}}}async function D(n){let t=await n();return t?t.error?t.error==="TokenExpired"?{status:"token_expired",session:t}:{status:"error",session:t,error:t.error}:{status:"authenticated",session:t}:{status:"unauthenticated",session:null}}function F(n,t){return async function(e){let o=await I(n,e);o.authError&&t(o.authError);let{authError:a,...s}=o;return s}}function U(n,t){return async function(){let e=await w(n);e.authError&&t(e.authError);let{authError:o,...a}=e;return a}}function H(n,t){return {getAuthProps:U(n,t),getData:F(n,t)}}async function X(n,t,r={}){let e=await D(n);switch(e.status){case"authenticated":return t(e.session);case"token_expired":return r.onTokenExpired!==void 0?typeof r.onTokenExpired=="function"?r.onTokenExpired():r.onTokenExpired:t(e.session);case"unauthenticated":if(r.onUnauthenticated!==void 0)return typeof r.onUnauthenticated=="function"?r.onUnauthenticated():r.onUnauthenticated;throw new Error("Unauthorized: No active session");case"error":if(r.onError!==void 0)return typeof r.onError=="function"?r.onError(e.error):r.onError;throw new Error(`Unauthorized: ${e.error}`);default:throw new Error("Unknown auth state")}}function B(n,t={}){let{loginUrl:r="/login",protectedPaths:e,publicPaths:o}=t;return async function(s){let{pathname:c}=s.nextUrl;if(o&&o.some(u=>typeof u=="string"?p(c,u):u.test(c)))return server.NextResponse.next();if(e&&!e.some(u=>typeof u=="string"?p(c,u):u.test(c)))return server.NextResponse.next();let l=await n();if(!l){let i=new URL(r,s.url),u=s.nextUrl.search?`${c}${s.nextUrl.search}`:c;return i.searchParams.set("returnTo",u),server.NextResponse.redirect(i)}if(l.error&&l.error!=="TokenExpired"){let i=new URL(r,s.url),u=s.nextUrl.search?`${c}${s.nextUrl.search}`:c;return i.searchParams.set("returnTo",u),i.searchParams.set("error",l.error),server.NextResponse.redirect(i)}return server.NextResponse.next()}}function K(n,t){return async(...r)=>{let e=await n();if(!e)throw new Error("Unauthorized: No active session");if(e.error&&e.error!=="TokenExpired")throw new Error(`Unauthorized: ${e.error}`);return t(e,...r)}}
|
|
68
13
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
return await response.json();
|
|
84
|
-
} catch (error) {
|
|
85
|
-
console.error("[auth-next-server] Token validation error:", error);
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
function createAuthConfig(config) {
|
|
90
|
-
const authDomain = config.authenticationDomain || DEFAULT_AUTH_DOMAIN;
|
|
91
|
-
return {
|
|
92
|
-
providers: [
|
|
93
|
-
Credentials({
|
|
94
|
-
id: IMMUTABLE_PROVIDER_ID,
|
|
95
|
-
name: "Immutable",
|
|
96
|
-
credentials: {
|
|
97
|
-
tokens: { label: "Tokens", type: "text" }
|
|
98
|
-
},
|
|
99
|
-
async authorize(credentials) {
|
|
100
|
-
if (!credentials?.tokens || typeof credentials.tokens !== "string") {
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
let tokenData;
|
|
104
|
-
try {
|
|
105
|
-
tokenData = JSON.parse(credentials.tokens);
|
|
106
|
-
} catch (error) {
|
|
107
|
-
console.error("[auth-next-server] Failed to parse token data:", error);
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
if (!tokenData.accessToken || typeof tokenData.accessToken !== "string" || !tokenData.profile || typeof tokenData.profile !== "object" || !tokenData.profile.sub || typeof tokenData.profile.sub !== "string" || typeof tokenData.accessTokenExpires !== "number" || Number.isNaN(tokenData.accessTokenExpires)) {
|
|
111
|
-
console.error("[auth-next-server] Invalid token data structure - missing required fields");
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
114
|
-
const userInfo = await validateTokens(tokenData.accessToken, authDomain);
|
|
115
|
-
if (!userInfo) {
|
|
116
|
-
console.error("[auth-next-server] Token validation failed - rejecting authentication");
|
|
117
|
-
return null;
|
|
118
|
-
}
|
|
119
|
-
if (userInfo.sub !== tokenData.profile.sub) {
|
|
120
|
-
console.error(
|
|
121
|
-
"[auth-next-server] User ID mismatch - userinfo sub:",
|
|
122
|
-
userInfo.sub,
|
|
123
|
-
"provided sub:",
|
|
124
|
-
tokenData.profile.sub
|
|
125
|
-
);
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
return {
|
|
129
|
-
id: userInfo.sub,
|
|
130
|
-
sub: userInfo.sub,
|
|
131
|
-
email: userInfo.email ?? tokenData.profile.email,
|
|
132
|
-
nickname: userInfo.nickname ?? tokenData.profile.nickname,
|
|
133
|
-
accessToken: tokenData.accessToken,
|
|
134
|
-
refreshToken: tokenData.refreshToken,
|
|
135
|
-
idToken: tokenData.idToken,
|
|
136
|
-
accessTokenExpires: tokenData.accessTokenExpires,
|
|
137
|
-
zkEvm: tokenData.zkEvm
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
})
|
|
141
|
-
],
|
|
142
|
-
callbacks: {
|
|
143
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
144
|
-
async jwt({
|
|
145
|
-
token,
|
|
146
|
-
user,
|
|
147
|
-
trigger,
|
|
148
|
-
session: sessionUpdate
|
|
149
|
-
}) {
|
|
150
|
-
if (user) {
|
|
151
|
-
return {
|
|
152
|
-
...token,
|
|
153
|
-
sub: user.sub,
|
|
154
|
-
email: user.email,
|
|
155
|
-
nickname: user.nickname,
|
|
156
|
-
accessToken: user.accessToken,
|
|
157
|
-
refreshToken: user.refreshToken,
|
|
158
|
-
idToken: user.idToken,
|
|
159
|
-
accessTokenExpires: user.accessTokenExpires,
|
|
160
|
-
zkEvm: user.zkEvm
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
if (trigger === "update" && sessionUpdate) {
|
|
164
|
-
const update = sessionUpdate;
|
|
165
|
-
return {
|
|
166
|
-
...token,
|
|
167
|
-
...update.accessToken ? { accessToken: update.accessToken } : {},
|
|
168
|
-
...update.refreshToken ? { refreshToken: update.refreshToken } : {},
|
|
169
|
-
...update.idToken ? { idToken: update.idToken } : {},
|
|
170
|
-
...update.accessTokenExpires ? { accessTokenExpires: update.accessTokenExpires } : {},
|
|
171
|
-
...update.zkEvm ? { zkEvm: update.zkEvm } : {},
|
|
172
|
-
// Clear any stale error when valid tokens are synced from client-side
|
|
173
|
-
error: void 0
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
if (!isTokenExpired(token.accessTokenExpires)) {
|
|
177
|
-
return token;
|
|
178
|
-
}
|
|
179
|
-
return {
|
|
180
|
-
...token,
|
|
181
|
-
error: "TokenExpired"
|
|
182
|
-
};
|
|
183
|
-
},
|
|
184
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
185
|
-
async session({ session, token }) {
|
|
186
|
-
return {
|
|
187
|
-
...session,
|
|
188
|
-
user: {
|
|
189
|
-
...session.user,
|
|
190
|
-
sub: token.sub,
|
|
191
|
-
email: token.email,
|
|
192
|
-
nickname: token.nickname
|
|
193
|
-
},
|
|
194
|
-
accessToken: token.accessToken,
|
|
195
|
-
refreshToken: token.refreshToken,
|
|
196
|
-
idToken: token.idToken,
|
|
197
|
-
accessTokenExpires: token.accessTokenExpires,
|
|
198
|
-
zkEvm: token.zkEvm,
|
|
199
|
-
...token.error && { error: token.error }
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
},
|
|
203
|
-
session: {
|
|
204
|
-
strategy: "jwt",
|
|
205
|
-
// Session max age in seconds (365 days default)
|
|
206
|
-
maxAge: DEFAULT_SESSION_MAX_AGE_SECONDS
|
|
207
|
-
}
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
var createAuthOptions = createAuthConfig;
|
|
211
|
-
|
|
212
|
-
// src/utils/pathMatch.ts
|
|
213
|
-
function matchPathPrefix(pathname, pattern) {
|
|
214
|
-
if (pathname === pattern) return true;
|
|
215
|
-
const prefix = pattern.endsWith("/") ? pattern : `${pattern}/`;
|
|
216
|
-
return pathname.startsWith(prefix);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// src/index.ts
|
|
220
|
-
var NextAuth = import_next_auth.default.default || import_next_auth.default;
|
|
221
|
-
function createImmutableAuth(config, overrides) {
|
|
222
|
-
const baseConfig = createAuthConfig(config);
|
|
223
|
-
if (!overrides) {
|
|
224
|
-
return NextAuth(baseConfig);
|
|
225
|
-
}
|
|
226
|
-
const { callbacks: overrideCallbacks, ...otherOverrides } = overrides;
|
|
227
|
-
const composedCallbacks = { ...baseConfig.callbacks };
|
|
228
|
-
if (overrideCallbacks) {
|
|
229
|
-
if (overrideCallbacks.jwt) {
|
|
230
|
-
const baseJwt = baseConfig.callbacks?.jwt;
|
|
231
|
-
const userJwt = overrideCallbacks.jwt;
|
|
232
|
-
composedCallbacks.jwt = async (params) => {
|
|
233
|
-
const result = baseJwt ? await baseJwt(params) : params.token;
|
|
234
|
-
return userJwt({ ...params, token: result });
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
if (overrideCallbacks.session) {
|
|
238
|
-
const baseSession = baseConfig.callbacks?.session;
|
|
239
|
-
const userSession = overrideCallbacks.session;
|
|
240
|
-
composedCallbacks.session = async (params) => {
|
|
241
|
-
const result = baseSession ? await baseSession(params) : params.session;
|
|
242
|
-
return userSession({ ...params, session: result });
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
if (overrideCallbacks.signIn) {
|
|
246
|
-
composedCallbacks.signIn = overrideCallbacks.signIn;
|
|
247
|
-
}
|
|
248
|
-
if (overrideCallbacks.redirect) {
|
|
249
|
-
composedCallbacks.redirect = overrideCallbacks.redirect;
|
|
250
|
-
}
|
|
251
|
-
if (overrideCallbacks.authorized) {
|
|
252
|
-
composedCallbacks.authorized = overrideCallbacks.authorized;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
const mergedConfig = {
|
|
256
|
-
...baseConfig,
|
|
257
|
-
...otherOverrides,
|
|
258
|
-
callbacks: composedCallbacks
|
|
259
|
-
};
|
|
260
|
-
return NextAuth(mergedConfig);
|
|
261
|
-
}
|
|
262
|
-
async function getAuthProps(auth) {
|
|
263
|
-
const session = await auth();
|
|
264
|
-
if (!session) {
|
|
265
|
-
return { session: null, ssr: false };
|
|
266
|
-
}
|
|
267
|
-
if (session.error === "TokenExpired") {
|
|
268
|
-
return { session: null, ssr: false };
|
|
269
|
-
}
|
|
270
|
-
if (session.error) {
|
|
271
|
-
return { session: null, ssr: false, authError: session.error };
|
|
272
|
-
}
|
|
273
|
-
return { session, ssr: true };
|
|
274
|
-
}
|
|
275
|
-
async function getAuthenticatedData(auth, fetcher) {
|
|
276
|
-
const session = await auth();
|
|
277
|
-
if (!session) {
|
|
278
|
-
return { session: null, ssr: false, data: null };
|
|
279
|
-
}
|
|
280
|
-
if (session.error === "TokenExpired") {
|
|
281
|
-
return { session: null, ssr: false, data: null };
|
|
282
|
-
}
|
|
283
|
-
if (session.error) {
|
|
284
|
-
return {
|
|
285
|
-
session: null,
|
|
286
|
-
ssr: false,
|
|
287
|
-
data: null,
|
|
288
|
-
authError: session.error
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
try {
|
|
292
|
-
const data = await fetcher(session.accessToken);
|
|
293
|
-
return { session, ssr: true, data };
|
|
294
|
-
} catch (err) {
|
|
295
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
296
|
-
return {
|
|
297
|
-
session,
|
|
298
|
-
ssr: true,
|
|
299
|
-
data: null,
|
|
300
|
-
fetchError: errorMessage
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
async function getValidSession(auth) {
|
|
305
|
-
const session = await auth();
|
|
306
|
-
if (!session) {
|
|
307
|
-
return { status: "unauthenticated", session: null };
|
|
308
|
-
}
|
|
309
|
-
if (!session.error) {
|
|
310
|
-
return { status: "authenticated", session };
|
|
311
|
-
}
|
|
312
|
-
if (session.error === "TokenExpired") {
|
|
313
|
-
return { status: "token_expired", session };
|
|
314
|
-
}
|
|
315
|
-
return { status: "error", session, error: session.error };
|
|
316
|
-
}
|
|
317
|
-
function createProtectedDataFetcher(auth, onAuthError) {
|
|
318
|
-
return async function getProtectedData(fetcher) {
|
|
319
|
-
const result = await getAuthenticatedData(auth, fetcher);
|
|
320
|
-
if (result.authError) {
|
|
321
|
-
onAuthError(result.authError);
|
|
322
|
-
}
|
|
323
|
-
const { authError: handledAuthError, ...props } = result;
|
|
324
|
-
return props;
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
function createProtectedAuthProps(auth, onAuthError) {
|
|
328
|
-
return async function getProtectedAuth() {
|
|
329
|
-
const result = await getAuthProps(auth);
|
|
330
|
-
if (result.authError) {
|
|
331
|
-
onAuthError(result.authError);
|
|
332
|
-
}
|
|
333
|
-
const { authError: handledAuthError, ...props } = result;
|
|
334
|
-
return props;
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
function createProtectedFetchers(auth, onAuthError) {
|
|
338
|
-
return {
|
|
339
|
-
getAuthProps: createProtectedAuthProps(auth, onAuthError),
|
|
340
|
-
getData: createProtectedDataFetcher(auth, onAuthError)
|
|
341
|
-
};
|
|
342
|
-
}
|
|
343
|
-
async function withServerAuth(auth, serverRender, options = {}) {
|
|
344
|
-
const result = await getValidSession(auth);
|
|
345
|
-
switch (result.status) {
|
|
346
|
-
case "authenticated":
|
|
347
|
-
return serverRender(result.session);
|
|
348
|
-
case "token_expired":
|
|
349
|
-
if (options.onTokenExpired !== void 0) {
|
|
350
|
-
return typeof options.onTokenExpired === "function" ? options.onTokenExpired() : options.onTokenExpired;
|
|
351
|
-
}
|
|
352
|
-
return serverRender(result.session);
|
|
353
|
-
case "unauthenticated":
|
|
354
|
-
if (options.onUnauthenticated !== void 0) {
|
|
355
|
-
return typeof options.onUnauthenticated === "function" ? options.onUnauthenticated() : options.onUnauthenticated;
|
|
356
|
-
}
|
|
357
|
-
throw new Error("Unauthorized: No active session");
|
|
358
|
-
case "error":
|
|
359
|
-
if (options.onError !== void 0) {
|
|
360
|
-
return typeof options.onError === "function" ? options.onError(result.error) : options.onError;
|
|
361
|
-
}
|
|
362
|
-
throw new Error(`Unauthorized: ${result.error}`);
|
|
363
|
-
default:
|
|
364
|
-
throw new Error("Unknown auth state");
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
function createAuthMiddleware(auth, options = {}) {
|
|
368
|
-
const { loginUrl = "/login", protectedPaths, publicPaths } = options;
|
|
369
|
-
return async function middleware(request) {
|
|
370
|
-
const { pathname } = request.nextUrl;
|
|
371
|
-
if (publicPaths) {
|
|
372
|
-
const isPublic = publicPaths.some((pattern) => {
|
|
373
|
-
if (typeof pattern === "string") {
|
|
374
|
-
return matchPathPrefix(pathname, pattern);
|
|
375
|
-
}
|
|
376
|
-
return pattern.test(pathname);
|
|
377
|
-
});
|
|
378
|
-
if (isPublic) {
|
|
379
|
-
return import_server.NextResponse.next();
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
if (protectedPaths) {
|
|
383
|
-
const isProtected = protectedPaths.some((pattern) => {
|
|
384
|
-
if (typeof pattern === "string") {
|
|
385
|
-
return matchPathPrefix(pathname, pattern);
|
|
386
|
-
}
|
|
387
|
-
return pattern.test(pathname);
|
|
388
|
-
});
|
|
389
|
-
if (!isProtected) {
|
|
390
|
-
return import_server.NextResponse.next();
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
const session = await auth();
|
|
394
|
-
if (!session) {
|
|
395
|
-
const url = new URL(loginUrl, request.url);
|
|
396
|
-
const returnTo = request.nextUrl.search ? `${pathname}${request.nextUrl.search}` : pathname;
|
|
397
|
-
url.searchParams.set("returnTo", returnTo);
|
|
398
|
-
return import_server.NextResponse.redirect(url);
|
|
399
|
-
}
|
|
400
|
-
if (session.error && session.error !== "TokenExpired") {
|
|
401
|
-
const url = new URL(loginUrl, request.url);
|
|
402
|
-
const returnTo = request.nextUrl.search ? `${pathname}${request.nextUrl.search}` : pathname;
|
|
403
|
-
url.searchParams.set("returnTo", returnTo);
|
|
404
|
-
url.searchParams.set("error", session.error);
|
|
405
|
-
return import_server.NextResponse.redirect(url);
|
|
406
|
-
}
|
|
407
|
-
return import_server.NextResponse.next();
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
function withAuth(auth, handler) {
|
|
411
|
-
return async (...args) => {
|
|
412
|
-
const session = await auth();
|
|
413
|
-
if (!session) {
|
|
414
|
-
throw new Error("Unauthorized: No active session");
|
|
415
|
-
}
|
|
416
|
-
if (session.error && session.error !== "TokenExpired") {
|
|
417
|
-
throw new Error(`Unauthorized: ${session.error}`);
|
|
418
|
-
}
|
|
419
|
-
return handler(session, ...args);
|
|
420
|
-
};
|
|
421
|
-
}
|
|
422
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
423
|
-
0 && (module.exports = {
|
|
424
|
-
createAuthConfig,
|
|
425
|
-
createAuthMiddleware,
|
|
426
|
-
createAuthOptions,
|
|
427
|
-
createImmutableAuth,
|
|
428
|
-
createProtectedAuthProps,
|
|
429
|
-
createProtectedDataFetcher,
|
|
430
|
-
createProtectedFetchers,
|
|
431
|
-
getAuthProps,
|
|
432
|
-
getAuthenticatedData,
|
|
433
|
-
getValidSession,
|
|
434
|
-
withAuth,
|
|
435
|
-
withServerAuth
|
|
436
|
-
});
|
|
14
|
+
exports.createAuthConfig = f;
|
|
15
|
+
exports.createAuthMiddleware = B;
|
|
16
|
+
exports.createAuthOptions = y;
|
|
17
|
+
exports.createImmutableAuth = $;
|
|
18
|
+
exports.createProtectedAuthProps = U;
|
|
19
|
+
exports.createProtectedDataFetcher = F;
|
|
20
|
+
exports.createProtectedFetchers = H;
|
|
21
|
+
exports.getAuthProps = w;
|
|
22
|
+
exports.getAuthenticatedData = I;
|
|
23
|
+
exports.getValidSession = D;
|
|
24
|
+
exports.withAuth = K;
|
|
25
|
+
exports.withServerAuth = X;
|
package/dist/node/index.js
CHANGED
|
@@ -1,390 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import E from 'next-auth';
|
|
2
|
+
import { NextResponse } from 'next/server';
|
|
3
|
+
import k from 'next-auth/providers/credentials';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
import CredentialsImport from "next-auth/providers/credentials";
|
|
5
|
+
var d="https://auth.immutable.com";var T="immutable";function m(n,t=60){return typeof n!="number"||Number.isNaN(n)?!0:Date.now()>=n-t*1e3}var P=k.default||k;async function b(n,t){try{let r=await fetch(`${t}/userinfo`,{method:"GET",headers:{Authorization:`Bearer ${n}`}});return r.ok?await r.json():(console.error("[auth-next-server] Token validation failed:",r.status,r.statusText),null)}catch(r){return console.error("[auth-next-server] Token validation error:",r),null}}function f(n){let t=n.authenticationDomain||d;return {providers:[P({id:T,name:"Immutable",credentials:{tokens:{label:"Tokens",type:"text"}},async authorize(r){if(!r?.tokens||typeof r.tokens!="string")return null;let e;try{e=JSON.parse(r.tokens);}catch(a){return console.error("[auth-next-server] Failed to parse token data:",a),null}if(!e.accessToken||typeof e.accessToken!="string"||!e.profile||typeof e.profile!="object"||!e.profile.sub||typeof e.profile.sub!="string"||typeof e.accessTokenExpires!="number"||Number.isNaN(e.accessTokenExpires))return console.error("[auth-next-server] Invalid token data structure - missing required fields"),null;let o=await b(e.accessToken,t);return o?o.sub!==e.profile.sub?(console.error("[auth-next-server] User ID mismatch - userinfo sub:",o.sub,"provided sub:",e.profile.sub),null):{id:o.sub,sub:o.sub,email:o.email??e.profile.email,nickname:o.nickname??e.profile.nickname,accessToken:e.accessToken,refreshToken:e.refreshToken,idToken:e.idToken,accessTokenExpires:e.accessTokenExpires,zkEvm:e.zkEvm}:(console.error("[auth-next-server] Token validation failed - rejecting authentication"),null)}})],callbacks:{async jwt({token:r,user:e,trigger:o,session:a}){if(e)return {...r,sub:e.sub,email:e.email,nickname:e.nickname,accessToken:e.accessToken,refreshToken:e.refreshToken,idToken:e.idToken,accessTokenExpires:e.accessTokenExpires,zkEvm:e.zkEvm};if(o==="update"&&a){let s=a;return {...r,...s.accessToken?{accessToken:s.accessToken}:{},...s.refreshToken?{refreshToken:s.refreshToken}:{},...s.idToken?{idToken:s.idToken}:{},...s.accessTokenExpires?{accessTokenExpires:s.accessTokenExpires}:{},...s.zkEvm?{zkEvm:s.zkEvm}:{},error:void 0}}return m(r.accessTokenExpires)?{...r,error:"TokenExpired"}:r},async session({session:r,token:e}){return {...r,user:{...r.user,sub:e.sub,email:e.email,nickname:e.nickname},accessToken:e.accessToken,refreshToken:e.refreshToken,idToken:e.idToken,accessTokenExpires:e.accessTokenExpires,zkEvm:e.zkEvm,...e.error&&{error:e.error}}}},session:{strategy:"jwt",maxAge:31536e3}}}var y=f;function p(n,t){if(n===t)return !0;let r=t.endsWith("/")?t:`${t}/`;return n.startsWith(r)}var x=E.default||E;function $(n,t){let r=f(n);if(!t)return x(r);let{callbacks:e,...o}=t,a={...r.callbacks};if(e){if(e.jwt){let c=r.callbacks?.jwt,l=e.jwt;a.jwt=async i=>{let u=c?await c(i):i.token;return l({...i,token:u})};}if(e.session){let c=r.callbacks?.session,l=e.session;a.session=async i=>{let u=c?await c(i):i.session;return l({...i,session:u})};}e.signIn&&(a.signIn=e.signIn),e.redirect&&(a.redirect=e.redirect),e.authorized&&(a.authorized=e.authorized);}let s={...r,...o,callbacks:a};return x(s)}async function w(n){let t=await n();return t?t.error==="TokenExpired"?{session:null,ssr:!1}:t.error?{session:null,ssr:!1,authError:t.error}:{session:t,ssr:!0}:{session:null,ssr:!1}}async function I(n,t){let r=await n();if(!r)return {session:null,ssr:!1,data:null};if(r.error==="TokenExpired")return {session:null,ssr:!1,data:null};if(r.error)return {session:null,ssr:!1,data:null,authError:r.error};try{let e=await t(r.accessToken);return {session:r,ssr:!0,data:e}}catch(e){let o=e instanceof Error?e.message:String(e);return {session:r,ssr:!0,data:null,fetchError:o}}}async function D(n){let t=await n();return t?t.error?t.error==="TokenExpired"?{status:"token_expired",session:t}:{status:"error",session:t,error:t.error}:{status:"authenticated",session:t}:{status:"unauthenticated",session:null}}function F(n,t){return async function(e){let o=await I(n,e);o.authError&&t(o.authError);let{authError:a,...s}=o;return s}}function U(n,t){return async function(){let e=await w(n);e.authError&&t(e.authError);let{authError:o,...a}=e;return a}}function H(n,t){return {getAuthProps:U(n,t),getData:F(n,t)}}async function X(n,t,r={}){let e=await D(n);switch(e.status){case"authenticated":return t(e.session);case"token_expired":return r.onTokenExpired!==void 0?typeof r.onTokenExpired=="function"?r.onTokenExpired():r.onTokenExpired:t(e.session);case"unauthenticated":if(r.onUnauthenticated!==void 0)return typeof r.onUnauthenticated=="function"?r.onUnauthenticated():r.onUnauthenticated;throw new Error("Unauthorized: No active session");case"error":if(r.onError!==void 0)return typeof r.onError=="function"?r.onError(e.error):r.onError;throw new Error(`Unauthorized: ${e.error}`);default:throw new Error("Unknown auth state")}}function B(n,t={}){let{loginUrl:r="/login",protectedPaths:e,publicPaths:o}=t;return async function(s){let{pathname:c}=s.nextUrl;if(o&&o.some(u=>typeof u=="string"?p(c,u):u.test(c)))return NextResponse.next();if(e&&!e.some(u=>typeof u=="string"?p(c,u):u.test(c)))return NextResponse.next();let l=await n();if(!l){let i=new URL(r,s.url),u=s.nextUrl.search?`${c}${s.nextUrl.search}`:c;return i.searchParams.set("returnTo",u),NextResponse.redirect(i)}if(l.error&&l.error!=="TokenExpired"){let i=new URL(r,s.url),u=s.nextUrl.search?`${c}${s.nextUrl.search}`:c;return i.searchParams.set("returnTo",u),i.searchParams.set("error",l.error),NextResponse.redirect(i)}return NextResponse.next()}}function K(n,t){return async(...r)=>{let e=await n();if(!e)throw new Error("Unauthorized: No active session");if(e.error&&e.error!=="TokenExpired")throw new Error(`Unauthorized: ${e.error}`);return t(e,...r)}}
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
var DEFAULT_AUTH_DOMAIN = "https://auth.immutable.com";
|
|
10
|
-
var IMMUTABLE_PROVIDER_ID = "immutable";
|
|
11
|
-
var DEFAULT_TOKEN_EXPIRY_SECONDS = 900;
|
|
12
|
-
var DEFAULT_TOKEN_EXPIRY_MS = DEFAULT_TOKEN_EXPIRY_SECONDS * 1e3;
|
|
13
|
-
var TOKEN_EXPIRY_BUFFER_SECONDS = 60;
|
|
14
|
-
var DEFAULT_SESSION_MAX_AGE_SECONDS = 365 * 24 * 60 * 60;
|
|
15
|
-
|
|
16
|
-
// src/refresh.ts
|
|
17
|
-
function isTokenExpired(accessTokenExpires, bufferSeconds = TOKEN_EXPIRY_BUFFER_SECONDS) {
|
|
18
|
-
if (typeof accessTokenExpires !== "number" || Number.isNaN(accessTokenExpires)) {
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
return Date.now() >= accessTokenExpires - bufferSeconds * 1e3;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// src/config.ts
|
|
25
|
-
var Credentials = CredentialsImport.default || CredentialsImport;
|
|
26
|
-
async function validateTokens(accessToken, authDomain) {
|
|
27
|
-
try {
|
|
28
|
-
const response = await fetch(`${authDomain}/userinfo`, {
|
|
29
|
-
method: "GET",
|
|
30
|
-
headers: {
|
|
31
|
-
Authorization: `Bearer ${accessToken}`
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
if (!response.ok) {
|
|
35
|
-
console.error("[auth-next-server] Token validation failed:", response.status, response.statusText);
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
return await response.json();
|
|
39
|
-
} catch (error) {
|
|
40
|
-
console.error("[auth-next-server] Token validation error:", error);
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
function createAuthConfig(config) {
|
|
45
|
-
const authDomain = config.authenticationDomain || DEFAULT_AUTH_DOMAIN;
|
|
46
|
-
return {
|
|
47
|
-
providers: [
|
|
48
|
-
Credentials({
|
|
49
|
-
id: IMMUTABLE_PROVIDER_ID,
|
|
50
|
-
name: "Immutable",
|
|
51
|
-
credentials: {
|
|
52
|
-
tokens: { label: "Tokens", type: "text" }
|
|
53
|
-
},
|
|
54
|
-
async authorize(credentials) {
|
|
55
|
-
if (!credentials?.tokens || typeof credentials.tokens !== "string") {
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
let tokenData;
|
|
59
|
-
try {
|
|
60
|
-
tokenData = JSON.parse(credentials.tokens);
|
|
61
|
-
} catch (error) {
|
|
62
|
-
console.error("[auth-next-server] Failed to parse token data:", error);
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
if (!tokenData.accessToken || typeof tokenData.accessToken !== "string" || !tokenData.profile || typeof tokenData.profile !== "object" || !tokenData.profile.sub || typeof tokenData.profile.sub !== "string" || typeof tokenData.accessTokenExpires !== "number" || Number.isNaN(tokenData.accessTokenExpires)) {
|
|
66
|
-
console.error("[auth-next-server] Invalid token data structure - missing required fields");
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
const userInfo = await validateTokens(tokenData.accessToken, authDomain);
|
|
70
|
-
if (!userInfo) {
|
|
71
|
-
console.error("[auth-next-server] Token validation failed - rejecting authentication");
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
if (userInfo.sub !== tokenData.profile.sub) {
|
|
75
|
-
console.error(
|
|
76
|
-
"[auth-next-server] User ID mismatch - userinfo sub:",
|
|
77
|
-
userInfo.sub,
|
|
78
|
-
"provided sub:",
|
|
79
|
-
tokenData.profile.sub
|
|
80
|
-
);
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
return {
|
|
84
|
-
id: userInfo.sub,
|
|
85
|
-
sub: userInfo.sub,
|
|
86
|
-
email: userInfo.email ?? tokenData.profile.email,
|
|
87
|
-
nickname: userInfo.nickname ?? tokenData.profile.nickname,
|
|
88
|
-
accessToken: tokenData.accessToken,
|
|
89
|
-
refreshToken: tokenData.refreshToken,
|
|
90
|
-
idToken: tokenData.idToken,
|
|
91
|
-
accessTokenExpires: tokenData.accessTokenExpires,
|
|
92
|
-
zkEvm: tokenData.zkEvm
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
})
|
|
96
|
-
],
|
|
97
|
-
callbacks: {
|
|
98
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
99
|
-
async jwt({
|
|
100
|
-
token,
|
|
101
|
-
user,
|
|
102
|
-
trigger,
|
|
103
|
-
session: sessionUpdate
|
|
104
|
-
}) {
|
|
105
|
-
if (user) {
|
|
106
|
-
return {
|
|
107
|
-
...token,
|
|
108
|
-
sub: user.sub,
|
|
109
|
-
email: user.email,
|
|
110
|
-
nickname: user.nickname,
|
|
111
|
-
accessToken: user.accessToken,
|
|
112
|
-
refreshToken: user.refreshToken,
|
|
113
|
-
idToken: user.idToken,
|
|
114
|
-
accessTokenExpires: user.accessTokenExpires,
|
|
115
|
-
zkEvm: user.zkEvm
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
if (trigger === "update" && sessionUpdate) {
|
|
119
|
-
const update = sessionUpdate;
|
|
120
|
-
return {
|
|
121
|
-
...token,
|
|
122
|
-
...update.accessToken ? { accessToken: update.accessToken } : {},
|
|
123
|
-
...update.refreshToken ? { refreshToken: update.refreshToken } : {},
|
|
124
|
-
...update.idToken ? { idToken: update.idToken } : {},
|
|
125
|
-
...update.accessTokenExpires ? { accessTokenExpires: update.accessTokenExpires } : {},
|
|
126
|
-
...update.zkEvm ? { zkEvm: update.zkEvm } : {},
|
|
127
|
-
// Clear any stale error when valid tokens are synced from client-side
|
|
128
|
-
error: void 0
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
if (!isTokenExpired(token.accessTokenExpires)) {
|
|
132
|
-
return token;
|
|
133
|
-
}
|
|
134
|
-
return {
|
|
135
|
-
...token,
|
|
136
|
-
error: "TokenExpired"
|
|
137
|
-
};
|
|
138
|
-
},
|
|
139
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
140
|
-
async session({ session, token }) {
|
|
141
|
-
return {
|
|
142
|
-
...session,
|
|
143
|
-
user: {
|
|
144
|
-
...session.user,
|
|
145
|
-
sub: token.sub,
|
|
146
|
-
email: token.email,
|
|
147
|
-
nickname: token.nickname
|
|
148
|
-
},
|
|
149
|
-
accessToken: token.accessToken,
|
|
150
|
-
refreshToken: token.refreshToken,
|
|
151
|
-
idToken: token.idToken,
|
|
152
|
-
accessTokenExpires: token.accessTokenExpires,
|
|
153
|
-
zkEvm: token.zkEvm,
|
|
154
|
-
...token.error && { error: token.error }
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
},
|
|
158
|
-
session: {
|
|
159
|
-
strategy: "jwt",
|
|
160
|
-
// Session max age in seconds (365 days default)
|
|
161
|
-
maxAge: DEFAULT_SESSION_MAX_AGE_SECONDS
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
var createAuthOptions = createAuthConfig;
|
|
166
|
-
|
|
167
|
-
// src/utils/pathMatch.ts
|
|
168
|
-
function matchPathPrefix(pathname, pattern) {
|
|
169
|
-
if (pathname === pattern) return true;
|
|
170
|
-
const prefix = pattern.endsWith("/") ? pattern : `${pattern}/`;
|
|
171
|
-
return pathname.startsWith(prefix);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// src/index.ts
|
|
175
|
-
var NextAuth = NextAuthImport.default || NextAuthImport;
|
|
176
|
-
function createImmutableAuth(config, overrides) {
|
|
177
|
-
const baseConfig = createAuthConfig(config);
|
|
178
|
-
if (!overrides) {
|
|
179
|
-
return NextAuth(baseConfig);
|
|
180
|
-
}
|
|
181
|
-
const { callbacks: overrideCallbacks, ...otherOverrides } = overrides;
|
|
182
|
-
const composedCallbacks = { ...baseConfig.callbacks };
|
|
183
|
-
if (overrideCallbacks) {
|
|
184
|
-
if (overrideCallbacks.jwt) {
|
|
185
|
-
const baseJwt = baseConfig.callbacks?.jwt;
|
|
186
|
-
const userJwt = overrideCallbacks.jwt;
|
|
187
|
-
composedCallbacks.jwt = async (params) => {
|
|
188
|
-
const result = baseJwt ? await baseJwt(params) : params.token;
|
|
189
|
-
return userJwt({ ...params, token: result });
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
if (overrideCallbacks.session) {
|
|
193
|
-
const baseSession = baseConfig.callbacks?.session;
|
|
194
|
-
const userSession = overrideCallbacks.session;
|
|
195
|
-
composedCallbacks.session = async (params) => {
|
|
196
|
-
const result = baseSession ? await baseSession(params) : params.session;
|
|
197
|
-
return userSession({ ...params, session: result });
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
if (overrideCallbacks.signIn) {
|
|
201
|
-
composedCallbacks.signIn = overrideCallbacks.signIn;
|
|
202
|
-
}
|
|
203
|
-
if (overrideCallbacks.redirect) {
|
|
204
|
-
composedCallbacks.redirect = overrideCallbacks.redirect;
|
|
205
|
-
}
|
|
206
|
-
if (overrideCallbacks.authorized) {
|
|
207
|
-
composedCallbacks.authorized = overrideCallbacks.authorized;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
const mergedConfig = {
|
|
211
|
-
...baseConfig,
|
|
212
|
-
...otherOverrides,
|
|
213
|
-
callbacks: composedCallbacks
|
|
214
|
-
};
|
|
215
|
-
return NextAuth(mergedConfig);
|
|
216
|
-
}
|
|
217
|
-
async function getAuthProps(auth) {
|
|
218
|
-
const session = await auth();
|
|
219
|
-
if (!session) {
|
|
220
|
-
return { session: null, ssr: false };
|
|
221
|
-
}
|
|
222
|
-
if (session.error === "TokenExpired") {
|
|
223
|
-
return { session: null, ssr: false };
|
|
224
|
-
}
|
|
225
|
-
if (session.error) {
|
|
226
|
-
return { session: null, ssr: false, authError: session.error };
|
|
227
|
-
}
|
|
228
|
-
return { session, ssr: true };
|
|
229
|
-
}
|
|
230
|
-
async function getAuthenticatedData(auth, fetcher) {
|
|
231
|
-
const session = await auth();
|
|
232
|
-
if (!session) {
|
|
233
|
-
return { session: null, ssr: false, data: null };
|
|
234
|
-
}
|
|
235
|
-
if (session.error === "TokenExpired") {
|
|
236
|
-
return { session: null, ssr: false, data: null };
|
|
237
|
-
}
|
|
238
|
-
if (session.error) {
|
|
239
|
-
return {
|
|
240
|
-
session: null,
|
|
241
|
-
ssr: false,
|
|
242
|
-
data: null,
|
|
243
|
-
authError: session.error
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
try {
|
|
247
|
-
const data = await fetcher(session.accessToken);
|
|
248
|
-
return { session, ssr: true, data };
|
|
249
|
-
} catch (err) {
|
|
250
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
251
|
-
return {
|
|
252
|
-
session,
|
|
253
|
-
ssr: true,
|
|
254
|
-
data: null,
|
|
255
|
-
fetchError: errorMessage
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
async function getValidSession(auth) {
|
|
260
|
-
const session = await auth();
|
|
261
|
-
if (!session) {
|
|
262
|
-
return { status: "unauthenticated", session: null };
|
|
263
|
-
}
|
|
264
|
-
if (!session.error) {
|
|
265
|
-
return { status: "authenticated", session };
|
|
266
|
-
}
|
|
267
|
-
if (session.error === "TokenExpired") {
|
|
268
|
-
return { status: "token_expired", session };
|
|
269
|
-
}
|
|
270
|
-
return { status: "error", session, error: session.error };
|
|
271
|
-
}
|
|
272
|
-
function createProtectedDataFetcher(auth, onAuthError) {
|
|
273
|
-
return async function getProtectedData(fetcher) {
|
|
274
|
-
const result = await getAuthenticatedData(auth, fetcher);
|
|
275
|
-
if (result.authError) {
|
|
276
|
-
onAuthError(result.authError);
|
|
277
|
-
}
|
|
278
|
-
const { authError: handledAuthError, ...props } = result;
|
|
279
|
-
return props;
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
function createProtectedAuthProps(auth, onAuthError) {
|
|
283
|
-
return async function getProtectedAuth() {
|
|
284
|
-
const result = await getAuthProps(auth);
|
|
285
|
-
if (result.authError) {
|
|
286
|
-
onAuthError(result.authError);
|
|
287
|
-
}
|
|
288
|
-
const { authError: handledAuthError, ...props } = result;
|
|
289
|
-
return props;
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
function createProtectedFetchers(auth, onAuthError) {
|
|
293
|
-
return {
|
|
294
|
-
getAuthProps: createProtectedAuthProps(auth, onAuthError),
|
|
295
|
-
getData: createProtectedDataFetcher(auth, onAuthError)
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
async function withServerAuth(auth, serverRender, options = {}) {
|
|
299
|
-
const result = await getValidSession(auth);
|
|
300
|
-
switch (result.status) {
|
|
301
|
-
case "authenticated":
|
|
302
|
-
return serverRender(result.session);
|
|
303
|
-
case "token_expired":
|
|
304
|
-
if (options.onTokenExpired !== void 0) {
|
|
305
|
-
return typeof options.onTokenExpired === "function" ? options.onTokenExpired() : options.onTokenExpired;
|
|
306
|
-
}
|
|
307
|
-
return serverRender(result.session);
|
|
308
|
-
case "unauthenticated":
|
|
309
|
-
if (options.onUnauthenticated !== void 0) {
|
|
310
|
-
return typeof options.onUnauthenticated === "function" ? options.onUnauthenticated() : options.onUnauthenticated;
|
|
311
|
-
}
|
|
312
|
-
throw new Error("Unauthorized: No active session");
|
|
313
|
-
case "error":
|
|
314
|
-
if (options.onError !== void 0) {
|
|
315
|
-
return typeof options.onError === "function" ? options.onError(result.error) : options.onError;
|
|
316
|
-
}
|
|
317
|
-
throw new Error(`Unauthorized: ${result.error}`);
|
|
318
|
-
default:
|
|
319
|
-
throw new Error("Unknown auth state");
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
function createAuthMiddleware(auth, options = {}) {
|
|
323
|
-
const { loginUrl = "/login", protectedPaths, publicPaths } = options;
|
|
324
|
-
return async function middleware(request) {
|
|
325
|
-
const { pathname } = request.nextUrl;
|
|
326
|
-
if (publicPaths) {
|
|
327
|
-
const isPublic = publicPaths.some((pattern) => {
|
|
328
|
-
if (typeof pattern === "string") {
|
|
329
|
-
return matchPathPrefix(pathname, pattern);
|
|
330
|
-
}
|
|
331
|
-
return pattern.test(pathname);
|
|
332
|
-
});
|
|
333
|
-
if (isPublic) {
|
|
334
|
-
return NextResponse.next();
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
if (protectedPaths) {
|
|
338
|
-
const isProtected = protectedPaths.some((pattern) => {
|
|
339
|
-
if (typeof pattern === "string") {
|
|
340
|
-
return matchPathPrefix(pathname, pattern);
|
|
341
|
-
}
|
|
342
|
-
return pattern.test(pathname);
|
|
343
|
-
});
|
|
344
|
-
if (!isProtected) {
|
|
345
|
-
return NextResponse.next();
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
const session = await auth();
|
|
349
|
-
if (!session) {
|
|
350
|
-
const url = new URL(loginUrl, request.url);
|
|
351
|
-
const returnTo = request.nextUrl.search ? `${pathname}${request.nextUrl.search}` : pathname;
|
|
352
|
-
url.searchParams.set("returnTo", returnTo);
|
|
353
|
-
return NextResponse.redirect(url);
|
|
354
|
-
}
|
|
355
|
-
if (session.error && session.error !== "TokenExpired") {
|
|
356
|
-
const url = new URL(loginUrl, request.url);
|
|
357
|
-
const returnTo = request.nextUrl.search ? `${pathname}${request.nextUrl.search}` : pathname;
|
|
358
|
-
url.searchParams.set("returnTo", returnTo);
|
|
359
|
-
url.searchParams.set("error", session.error);
|
|
360
|
-
return NextResponse.redirect(url);
|
|
361
|
-
}
|
|
362
|
-
return NextResponse.next();
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
function withAuth(auth, handler) {
|
|
366
|
-
return async (...args) => {
|
|
367
|
-
const session = await auth();
|
|
368
|
-
if (!session) {
|
|
369
|
-
throw new Error("Unauthorized: No active session");
|
|
370
|
-
}
|
|
371
|
-
if (session.error && session.error !== "TokenExpired") {
|
|
372
|
-
throw new Error(`Unauthorized: ${session.error}`);
|
|
373
|
-
}
|
|
374
|
-
return handler(session, ...args);
|
|
375
|
-
};
|
|
376
|
-
}
|
|
377
|
-
export {
|
|
378
|
-
createAuthConfig,
|
|
379
|
-
createAuthMiddleware,
|
|
380
|
-
createAuthOptions,
|
|
381
|
-
createImmutableAuth,
|
|
382
|
-
createProtectedAuthProps,
|
|
383
|
-
createProtectedDataFetcher,
|
|
384
|
-
createProtectedFetchers,
|
|
385
|
-
getAuthProps,
|
|
386
|
-
getAuthenticatedData,
|
|
387
|
-
getValidSession,
|
|
388
|
-
withAuth,
|
|
389
|
-
withServerAuth
|
|
390
|
-
};
|
|
7
|
+
export { f as createAuthConfig, B as createAuthMiddleware, y as createAuthOptions, $ as createImmutableAuth, U as createProtectedAuthProps, F as createProtectedDataFetcher, H as createProtectedFetchers, w as getAuthProps, I as getAuthenticatedData, D as getValidSession, K as withAuth, X as withServerAuth };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imtbl/auth-next-server",
|
|
3
|
-
"version": "2.12.5-alpha.
|
|
3
|
+
"version": "2.12.5-alpha.14",
|
|
4
4
|
"description": "Immutable Auth.js v5 integration for Next.js - Server-side utilities",
|
|
5
5
|
"author": "Immutable",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"type": "module",
|
|
12
12
|
"main": "./dist/node/index.cjs",
|
|
13
13
|
"module": "./dist/node/index.js",
|
|
14
|
-
"types": "./dist/
|
|
14
|
+
"types": "./dist/types/index.d.ts",
|
|
15
15
|
"exports": {
|
|
16
16
|
".": {
|
|
17
17
|
"development": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"default": "./dist/node/index.js"
|
|
21
21
|
},
|
|
22
22
|
"default": {
|
|
23
|
-
"types": "./dist/
|
|
23
|
+
"types": "./dist/types/index.d.ts",
|
|
24
24
|
"require": "./dist/node/index.cjs",
|
|
25
25
|
"default": "./dist/node/index.js"
|
|
26
26
|
}
|
|
@@ -51,10 +51,12 @@
|
|
|
51
51
|
"typescript": "^5.6.2"
|
|
52
52
|
},
|
|
53
53
|
"scripts": {
|
|
54
|
-
"build": "
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
54
|
+
"build": "pnpm transpile && pnpm typegen",
|
|
55
|
+
"transpile": "tsup src/index.ts --config ../../tsup.config.js",
|
|
56
|
+
"typegen": "tsc --customConditions default --emitDeclarationOnly --outDir dist/types",
|
|
57
|
+
"pack:root": "pnpm pack --pack-destination $(dirname $(pnpm root -w))",
|
|
58
|
+
"lint": "eslint ./src --ext .ts,.jsx,.tsx --max-warnings=0",
|
|
59
|
+
"typecheck": "tsc --customConditions default --noEmit --jsx preserve",
|
|
58
60
|
"test": "jest --passWithNoTests"
|
|
59
61
|
}
|
|
60
62
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|