@tuwaio/satellite-siwe-next-auth 0.3.4 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -25
- package/dist/index.d.mts +1 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.mjs +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -4,15 +4,15 @@
|
|
|
4
4
|
[](./LICENSE)
|
|
5
5
|
[](https://github.com/TuwaIO/satellite-connect/actions)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Robust server-side session authentication adapter mapping cryptographic signatures to the SIWE standard and NextAuth.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
## 🏛️ What is `@tuwaio/satellite-siwe-next-auth`?
|
|
12
12
|
|
|
13
|
-
`@tuwaio/satellite-siwe-next-auth`
|
|
13
|
+
`@tuwaio/satellite-siwe-next-auth` implements the session authentication logic for the Satellite framework in Next.js App Router environments. It maps user-provided cryptographic signatures directly to the SIWE standard, bridging them to active application sessions.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
By bypassing standard client-heavy authentication pipelines, this package utilizes server-encrypted **Iron Session** cookies to verify and enforce session state across API routes and Server Components.
|
|
16
16
|
|
|
17
17
|
Built on top of **Wagmi/Viem** for signature generation and verification.
|
|
18
18
|
|
|
@@ -46,10 +46,10 @@ pnpm add @tuwaio/satellite-siwe-next-auth siwe iron-session wagmi @wagmi/core vi
|
|
|
46
46
|
|
|
47
47
|
This package requires two **private** server environment variables for security:
|
|
48
48
|
|
|
49
|
-
| Variable
|
|
50
|
-
|
|
|
51
|
-
| `SIWE_SESSION_SECRET` | **Required.** A cryptographically secure secret (minimum 32 characters) used by Iron Session to encrypt the session cookie.
|
|
52
|
-
| `SIWE_SESSION_URL`
|
|
49
|
+
| Variable | Description |
|
|
50
|
+
| :-------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
51
|
+
| `SIWE_SESSION_SECRET` | **Required.** A cryptographically secure secret (minimum 32 characters) used by Iron Session to encrypt the session cookie. |
|
|
52
|
+
| `SIWE_SESSION_URL` | **Required.** The full base URL of your application (e.g., `http://localhost:3000` or `https://myapp.com`). Used for SIWE domain verification. |
|
|
53
53
|
|
|
54
54
|
**Example `.env`:**
|
|
55
55
|
|
|
@@ -146,14 +146,15 @@ export function SatelliteSiweProvider({ children }: { children: ReactNode }) {
|
|
|
146
146
|
return (
|
|
147
147
|
<SatelliteConnectProvider
|
|
148
148
|
// Pass the EVM adapter with SIWE integration
|
|
149
|
-
adapter={satelliteEVMAdapter(
|
|
149
|
+
adapter={satelliteEVMAdapter(
|
|
150
|
+
wagmiConfig,
|
|
151
|
+
wagmiConfig.chains as readonly [Chain, ...Chain[]],
|
|
152
|
+
siweEnabled ? signInWithSiwe : undefined,
|
|
153
|
+
)}
|
|
150
154
|
autoConnect={true}
|
|
151
155
|
>
|
|
152
156
|
{/* EVMConnectorsWatcher handles disconnections and account changes */}
|
|
153
|
-
<EVMConnectorsWatcher
|
|
154
|
-
wagmiConfig={wagmiConfig}
|
|
155
|
-
siwe={{ isSignedIn, isRejected, enabled: siweEnabled }}
|
|
156
|
-
/>
|
|
157
|
+
<EVMConnectorsWatcher wagmiConfig={wagmiConfig} siwe={{ isSignedIn, isRejected, enabled: siweEnabled }} />
|
|
157
158
|
{children}
|
|
158
159
|
</SatelliteConnectProvider>
|
|
159
160
|
);
|
|
@@ -168,13 +169,13 @@ The `createSiweApiHandler` accepts an optional configuration object to override
|
|
|
168
169
|
|
|
169
170
|
### Configuration Parameters (`SiweApiConfig` Type)
|
|
170
171
|
|
|
171
|
-
| Parameter
|
|
172
|
-
|
|
|
173
|
-
| `session.password`
|
|
174
|
-
| `session.cookieName`
|
|
175
|
-
| `session.cookieOptions` | `SiweCookieOptions`
|
|
176
|
-
| `options.afterVerify`
|
|
177
|
-
| `options.afterLogout`
|
|
172
|
+
| Parameter | Type | Default | Description |
|
|
173
|
+
| :---------------------- | :-------------------- | :----------------------------------------- | :------------------------------------------------------------------------------------------------------ |
|
|
174
|
+
| `session.password` | `string` | `SIWE_SESSION_SECRET` | Overrides the secret key for encryption. |
|
|
175
|
+
| `session.cookieName` | `string` | `'satellite_siwe'` | Overrides the name of the session cookie. |
|
|
176
|
+
| `session.cookieOptions` | `SiweCookieOptions` | `{ maxAge: 30 days, secure: false (dev) }` | Allows overriding standard cookie settings (e.g., `maxAge`). |
|
|
177
|
+
| `options.afterVerify` | `() => Promise<void>` | `undefined` | Hook executed **after** the SIWE signature is cryptographically verified. Ideal for fetching user data. |
|
|
178
|
+
| `options.afterLogout` | `() => Promise<void>` | `undefined` | Hook executed **after** the session cookie is destroyed. |
|
|
178
179
|
|
|
179
180
|
### Example Custom Initialization
|
|
180
181
|
|
|
@@ -186,21 +187,21 @@ import { createSiweApiHandler } from '@tuwaio/satellite-siwe-next-auth/server';
|
|
|
186
187
|
const siweApiHandler = createSiweApiHandler({
|
|
187
188
|
// Custom Session Settings
|
|
188
189
|
session: {
|
|
189
|
-
cookieName:
|
|
190
|
+
cookieName: 'my_app_session',
|
|
190
191
|
cookieOptions: {
|
|
191
192
|
maxAge: 60 * 60 * 24 * 7, // 7 days
|
|
192
|
-
}
|
|
193
|
+
},
|
|
193
194
|
},
|
|
194
195
|
// Custom Hooks
|
|
195
196
|
options: {
|
|
196
197
|
afterVerify: async () => {
|
|
197
198
|
// This logic runs on the server side after a valid signature is confirmed.
|
|
198
|
-
console.log(
|
|
199
|
+
console.log('User verified, ready to create DB record.');
|
|
199
200
|
},
|
|
200
201
|
afterLogout: () => {
|
|
201
|
-
console.log(
|
|
202
|
-
}
|
|
203
|
-
}
|
|
202
|
+
console.log('User session destroyed.');
|
|
203
|
+
},
|
|
204
|
+
},
|
|
204
205
|
});
|
|
205
206
|
|
|
206
207
|
export const { GET, POST, DELETE } = siweApiHandler;
|
package/dist/index.d.mts
CHANGED
|
@@ -2,7 +2,6 @@ import { S as SIWESession, a as SiweAuthContextType, b as SiweNextAuthProviderPr
|
|
|
2
2
|
export { C as ConfigurableMessageOptions, G as GetSiweMessageOptions, c as Session, d as SiweApiConfig, e as SiweApiHooks, f as SiweCookieOptions, g as SiweSessionData, h as SiweSessionSettings, i as UnconfigurableMessageOptions } from './types-DYvmUmv4.mjs';
|
|
3
3
|
import { Config } from '@wagmi/core';
|
|
4
4
|
import * as react from 'react';
|
|
5
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
5
|
import 'viem';
|
|
7
6
|
import 'viem/siwe';
|
|
8
7
|
|
|
@@ -58,6 +57,6 @@ declare const SiweAuthContext: react.Context<SiweAuthContextType | undefined>;
|
|
|
58
57
|
* It must be nested inside NextAuth's `<SessionProvider>` and your Wagmi Provider.
|
|
59
58
|
* * **Note**: This provider requires the server-side NextAuth configuration to be set up.
|
|
60
59
|
*/
|
|
61
|
-
declare function SiweNextAuthProvider(props: SiweNextAuthProviderProps):
|
|
60
|
+
declare function SiweNextAuthProvider(props: SiweNextAuthProviderProps): react.JSX.Element;
|
|
62
61
|
|
|
63
62
|
export { SIWESession, SiweAuthContext, SiweAuthContextType, SiweNextAuthProvider, SiweNextAuthProviderProps, UseSiweSignatureResult, useInterval, useSiweAuth, useSiweAuthAdapter, useSiweSignature };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { S as SIWESession, a as SiweAuthContextType, b as SiweNextAuthProviderPr
|
|
|
2
2
|
export { C as ConfigurableMessageOptions, G as GetSiweMessageOptions, c as Session, d as SiweApiConfig, e as SiweApiHooks, f as SiweCookieOptions, g as SiweSessionData, h as SiweSessionSettings, i as UnconfigurableMessageOptions } from './types-DYvmUmv4.js';
|
|
3
3
|
import { Config } from '@wagmi/core';
|
|
4
4
|
import * as react from 'react';
|
|
5
|
-
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
5
|
import 'viem';
|
|
7
6
|
import 'viem/siwe';
|
|
8
7
|
|
|
@@ -58,6 +57,6 @@ declare const SiweAuthContext: react.Context<SiweAuthContextType | undefined>;
|
|
|
58
57
|
* It must be nested inside NextAuth's `<SessionProvider>` and your Wagmi Provider.
|
|
59
58
|
* * **Note**: This provider requires the server-side NextAuth configuration to be set up.
|
|
60
59
|
*/
|
|
61
|
-
declare function SiweNextAuthProvider(props: SiweNextAuthProviderProps):
|
|
60
|
+
declare function SiweNextAuthProvider(props: SiweNextAuthProviderProps): react.JSX.Element;
|
|
62
61
|
|
|
63
62
|
export { SIWESession, SiweAuthContext, SiweAuthContextType, SiweNextAuthProvider, SiweNextAuthProviderProps, UseSiweSignatureResult, useInterval, useSiweAuth, useSiweAuthAdapter, useSiweSignature };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
'use strict';var react=require('react'),core=require('@wagmi/core'),wagmi=require('wagmi'),siwe=require('viem/siwe'),jsxRuntime=require('react/jsx-runtime');function
|
|
1
|
+
'use strict';var react=require('react'),core=require('@wagmi/core'),wagmi=require('wagmi'),siwe=require('viem/siwe'),jsxRuntime=require('react/jsx-runtime');function M(t,e){let r=react.useRef(t);react.useEffect(()=>{r.current=t;},[t]),react.useEffect(()=>{if(e!==null&&typeof window<"u"&&window.setInterval){let a=window.setInterval(()=>r.current(),e);return ()=>window.clearInterval(a)}},[e]);}var x=react.createContext(void 0);function de(t){let e=react.useContext(x);if(e===void 0)throw new Error("useSiweAuth must be used within a SiweNextAuthProvider");let r=react.useCallback(async()=>e.signInWithSiwe(t?.onSignIn),[e.signInWithSiwe,t?.onSignIn]),a=react.useCallback(async()=>e.signOutSiwe(t?.onSignOut),[e.signOutSiwe,t?.onSignOut]);return react.useMemo(()=>({...e,signInWithSiwe:r,signOutSiwe:a}),[e,r,a])}async function X(){return crypto.randomUUID().replace(/-/g,"")}function D({wagmiConfig:t}){let{isConnected:e,address:r,chainId:a}=wagmi.useConnection({config:t}),[f,d]=react.useState(false),u=react.useMemo(()=>e&&!!r&&!!a,[e,r,a]);return react.useEffect(()=>{u&&d(false);},[u]),{getSiweSignature:async S=>{d(false);let n=core.getConnection(t);if(!n.isConnected||!n.address||!n.chainId)throw new Error("Connector not connected or connection details are missing from Wagmi snapshot.");try{let o=await X();if(!o)throw new Error("Failed to retrieve CSRF token/nonce.");let c=siwe.createSiweMessage({domain:window.location.host,statement:"Sign in with Ethereum to the application.",uri:window.location.origin,version:"1",...S?S():{},address:n.address,chainId:n.chainId,nonce:o}),w=await core.signMessage(t,{message:c});if(!w)throw d(!0),await core.disconnect(t),new Error("Message signing cancelled by user or failed.");return {message:c,signature:w}}catch(o){await core.disconnect(t),console.error("Error during signature generation:",o);let c=o;throw (c.name==="UserRejectedRequestError"||c.code===4001||/user rejected/i.test(c.message))&&d(true),o}},isReadyToSign:u,isRejected:f}}async function ee(){try{let t=await fetch("/api/siwe/session");if(t.status===401||t.status===404)return {session:void 0,status:"unauthenticated"};if(!t.ok)throw new Error("Failed to fetch session data.");let e=await t.json();return e.isLoggedIn&&e.address&&e.chainId?{session:{address:e.address,chainId:e.chainId},status:"authenticated"}:{session:void 0,status:"unauthenticated"}}catch(t){return console.error("Error fetching session:",t),{session:void 0,status:"unauthenticated"}}}function O({wagmiConfig:t,enabled:e=true,nonceRefetchInterval:r=300*1e3,onSignIn:a,onSignOut:f,getSiweMessageOptions:d}){let[u,p]=react.useState(void 0),[S,n]=react.useState("loading"),{isReadyToSign:o,getSiweSignature:c,isRejected:w}=D({wagmiConfig:t}),{address:y,chainId:v,isConnected:W}=wagmi.useConnection({config:t}),[P,T]=react.useState(false),g=S==="authenticated",R=S==="loading",N=u,F=react.useCallback(async()=>{n("loading");let{session:s,status:i}=await ee();return p(s),n(i),s},[]);M(()=>{g&&F();},r);let m=react.useCallback(async s=>{await fetch("/api/siwe/logout",{method:"POST"}),p(void 0),n("unauthenticated"),f?.(),s?.();},[f]),I=react.useCallback(async s=>{if(!e)throw new Error("SIWE is currently disabled via provider configuration.");n("loading");try{let i=await c(d);if(!i){n("unauthenticated");return}let l=await fetch("/api/siwe/login",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({message:i.message,signature:i.signature})}),h=await l.json();if(!l.ok||h.isLoggedIn!==!0)throw new Error(`Verification error: ${h.message||"Authentication failed."}`);console.log("SIWE Authentication successful.");let A={address:h.address,chainId:h.chainId};p(A),n("authenticated"),a?.(A),s?.(A);}catch(i){throw await core.disconnect(t),n("unauthenticated"),new Error(`SIWE Sign-In failed: ${i instanceof Error?i.message:"Unknown error"}`)}},[e,c,d,a,t]);return react.useEffect(()=>{if(g&&e){let s=u?.address?.toLowerCase(),i=y?.toLowerCase(),l=u?.chainId,h=v;s&&i&&s!==i||l&&h&&l!==h?(console.log("SIWE: Connector context changed (Address or Chain ID). Initiating re-authentication."),T(true),m()):!W&&(console.log("SIWE: Connector disconnected. Disconnecting session."),m(),f?.());}},[g,y,v,W,u,m,e,f]),react.useEffect(()=>{P&&S==="unauthenticated"&&o&&e&&(console.log("SIWE: State reset detected. Attempting automatic sign-in to establish new session."),T(false),I().catch(s=>{throw new Error(`SIWE Auto Sign-In failed after context change: ${s instanceof Error?s.message:"Unknown error"}`)}));},[P,S,o,I,e]),react.useMemo(()=>({data:N,isReadyToSign:o,isRejected:w,isLoading:R,isSignedIn:g,signInWithSiwe:I,signOutSiwe:m,enabled:e}),[N,o,w,R,g,I,m,e])}function We(t){let e=O(t);return jsxRuntime.jsx(x.Provider,{value:e,children:t.children})}exports.SiweAuthContext=x;exports.SiweNextAuthProvider=We;exports.useInterval=M;exports.useSiweAuth=de;exports.useSiweAuthAdapter=O;exports.useSiweSignature=D;
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import {createContext,useRef,useEffect,useContext,useCallback,useMemo,useState}from'react';import {getConnection,signMessage,disconnect}from'@wagmi/core';import {useConnection}from'wagmi';import {createSiweMessage}from'viem/siwe';import {jsx}from'react/jsx-runtime';function
|
|
1
|
+
import {createContext,useRef,useEffect,useContext,useCallback,useMemo,useState}from'react';import {getConnection,signMessage,disconnect}from'@wagmi/core';import {useConnection}from'wagmi';import {createSiweMessage}from'viem/siwe';import {jsx}from'react/jsx-runtime';function M(t,e){let r=useRef(t);useEffect(()=>{r.current=t;},[t]),useEffect(()=>{if(e!==null&&typeof window<"u"&&window.setInterval){let a=window.setInterval(()=>r.current(),e);return ()=>window.clearInterval(a)}},[e]);}var x=createContext(void 0);function de(t){let e=useContext(x);if(e===void 0)throw new Error("useSiweAuth must be used within a SiweNextAuthProvider");let r=useCallback(async()=>e.signInWithSiwe(t?.onSignIn),[e.signInWithSiwe,t?.onSignIn]),a=useCallback(async()=>e.signOutSiwe(t?.onSignOut),[e.signOutSiwe,t?.onSignOut]);return useMemo(()=>({...e,signInWithSiwe:r,signOutSiwe:a}),[e,r,a])}async function X(){return crypto.randomUUID().replace(/-/g,"")}function D({wagmiConfig:t}){let{isConnected:e,address:r,chainId:a}=useConnection({config:t}),[f,d]=useState(false),u=useMemo(()=>e&&!!r&&!!a,[e,r,a]);return useEffect(()=>{u&&d(false);},[u]),{getSiweSignature:async S=>{d(false);let n=getConnection(t);if(!n.isConnected||!n.address||!n.chainId)throw new Error("Connector not connected or connection details are missing from Wagmi snapshot.");try{let o=await X();if(!o)throw new Error("Failed to retrieve CSRF token/nonce.");let c=createSiweMessage({domain:window.location.host,statement:"Sign in with Ethereum to the application.",uri:window.location.origin,version:"1",...S?S():{},address:n.address,chainId:n.chainId,nonce:o}),w=await signMessage(t,{message:c});if(!w)throw d(!0),await disconnect(t),new Error("Message signing cancelled by user or failed.");return {message:c,signature:w}}catch(o){await disconnect(t),console.error("Error during signature generation:",o);let c=o;throw (c.name==="UserRejectedRequestError"||c.code===4001||/user rejected/i.test(c.message))&&d(true),o}},isReadyToSign:u,isRejected:f}}async function ee(){try{let t=await fetch("/api/siwe/session");if(t.status===401||t.status===404)return {session:void 0,status:"unauthenticated"};if(!t.ok)throw new Error("Failed to fetch session data.");let e=await t.json();return e.isLoggedIn&&e.address&&e.chainId?{session:{address:e.address,chainId:e.chainId},status:"authenticated"}:{session:void 0,status:"unauthenticated"}}catch(t){return console.error("Error fetching session:",t),{session:void 0,status:"unauthenticated"}}}function O({wagmiConfig:t,enabled:e=true,nonceRefetchInterval:r=300*1e3,onSignIn:a,onSignOut:f,getSiweMessageOptions:d}){let[u,p]=useState(void 0),[S,n]=useState("loading"),{isReadyToSign:o,getSiweSignature:c,isRejected:w}=D({wagmiConfig:t}),{address:y,chainId:v,isConnected:W}=useConnection({config:t}),[P,T]=useState(false),g=S==="authenticated",R=S==="loading",N=u,F=useCallback(async()=>{n("loading");let{session:s,status:i}=await ee();return p(s),n(i),s},[]);M(()=>{g&&F();},r);let m=useCallback(async s=>{await fetch("/api/siwe/logout",{method:"POST"}),p(void 0),n("unauthenticated"),f?.(),s?.();},[f]),I=useCallback(async s=>{if(!e)throw new Error("SIWE is currently disabled via provider configuration.");n("loading");try{let i=await c(d);if(!i){n("unauthenticated");return}let l=await fetch("/api/siwe/login",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({message:i.message,signature:i.signature})}),h=await l.json();if(!l.ok||h.isLoggedIn!==!0)throw new Error(`Verification error: ${h.message||"Authentication failed."}`);console.log("SIWE Authentication successful.");let A={address:h.address,chainId:h.chainId};p(A),n("authenticated"),a?.(A),s?.(A);}catch(i){throw await disconnect(t),n("unauthenticated"),new Error(`SIWE Sign-In failed: ${i instanceof Error?i.message:"Unknown error"}`)}},[e,c,d,a,t]);return useEffect(()=>{if(g&&e){let s=u?.address?.toLowerCase(),i=y?.toLowerCase(),l=u?.chainId,h=v;s&&i&&s!==i||l&&h&&l!==h?(console.log("SIWE: Connector context changed (Address or Chain ID). Initiating re-authentication."),T(true),m()):!W&&(console.log("SIWE: Connector disconnected. Disconnecting session."),m(),f?.());}},[g,y,v,W,u,m,e,f]),useEffect(()=>{P&&S==="unauthenticated"&&o&&e&&(console.log("SIWE: State reset detected. Attempting automatic sign-in to establish new session."),T(false),I().catch(s=>{throw new Error(`SIWE Auto Sign-In failed after context change: ${s instanceof Error?s.message:"Unknown error"}`)}));},[P,S,o,I,e]),useMemo(()=>({data:N,isReadyToSign:o,isRejected:w,isLoading:R,isSignedIn:g,signInWithSiwe:I,signOutSiwe:m,enabled:e}),[N,o,w,R,g,I,m,e])}function We(t){let e=O(t);return jsx(x.Provider,{value:e,children:t.children})}export{x as SiweAuthContext,We as SiweNextAuthProvider,M as useInterval,de as useSiweAuth,O as useSiweAuthAdapter,D as useSiweSignature};
|
package/dist/server/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var ironSession=require('iron-session'),server=require('next/server'),viem=require('viem'),siwe=require('viem/siwe');function l(t){let e=t.session||{},c=process.env.SIWE_SESSION_SECRET,a=e.password||c;if(!a||a.length<32)throw new Error("SIWE Error: Iron Session requires a 'password' option (min 32 chars) or SIWE_SESSION_SECRET environment variable to be set.");let S={...{secure:process.env.NODE_ENV==="production",maxAge:300*60,httpOnly:true,sameSite:"lax",path:"/"},...e.cookieOptions};return {password:a,cookieName:e.cookieName||"satellite_siwe",cookieOptions:S}}function
|
|
1
|
+
'use strict';var ironSession=require('iron-session'),server=require('next/server'),viem=require('viem'),siwe=require('viem/siwe');function l(t){let e=t.session||{},c=process.env.SIWE_SESSION_SECRET,a=e.password||c;if(!a||a.length<32)throw new Error("SIWE Error: Iron Session requires a 'password' option (min 32 chars) or SIWE_SESSION_SECRET environment variable to be set.");let S={...{secure:process.env.NODE_ENV==="production",maxAge:300*60,httpOnly:true,sameSite:"lax",path:"/"},...e.cookieOptions};return {password:a,cookieName:e.cookieName||"satellite_siwe",cookieOptions:S}}function L(t){if(!t)return console.warn("SIWE WARN: SIWE_SESSION_URL is not defined. Defaulting domain check to 'localhost'."),"localhost";try{return new URL(t.startsWith("http")?t:`https://${t}`).host}catch(e){return console.error(`SIWE ERROR: Invalid URL provided in SIWE_SESSION_URL: ${t}. Error: ${typeof e=="string"?e:e.message}`),"localhost"}}function _(t={}){let e=t.options||{},c=l(t);async function a(o){let s=new Response;return {session:await ironSession.getIronSession(o,s,c),response:s}}async function f(o){try{let{message:s,signature:d}=await o.json();if(!s||!d)return server.NextResponse.json({message:"Missing message or signature"},{status:400});e.afterNonce&&await e.afterNonce();let n=siwe.parseSiweMessage(s);if(!n||!n.address||!n.chainId)return server.NextResponse.json({message:"Invalid SIWE message format"},{status:400});let r=L(process.env.SIWE_SESSION_URL);if(!siwe.validateSiweMessage({message:n,domain:r}))return server.NextResponse.json({message:"SIWE message validation failed"},{status:401});if(!await viem.verifyMessage({address:n.address,message:s,signature:d}))return server.NextResponse.json({message:"SIWE signature verification failed"},{status:401});e.afterVerify&&await e.afterVerify();let{session:p,response:E}=await a(o);p.address=n.address,p.chainId=n.chainId,p.isLoggedIn=!0,await p.save(),e.afterSession&&await e.afterSession();let m=server.NextResponse.json({isLoggedIn:!0,address:p.address,chainId:p.chainId},{status:200});return E.headers.forEach((I,w)=>{w.toLowerCase()==="set-cookie"&&m.headers.append("Set-Cookie",I);}),m}catch(s){return console.error("SIWE CRITICAL AUTHENTICATION ERROR:",s),server.NextResponse.json({message:"Internal Server Error during session validation"},{status:500})}}async function S(o){let{session:s,response:d}=await a(o);if(o.method==="POST"||o.method==="DELETE"){s.destroy(),e.afterLogout&&await e.afterLogout();let n=server.NextResponse.json({isLoggedIn:false},{status:200});return d.headers.forEach((r,g)=>{g.toLowerCase()==="set-cookie"&&n.headers.append("Set-Cookie",r);}),n}return s.isLoggedIn&&s.address&&s.chainId?server.NextResponse.json({isLoggedIn:true,address:s.address,chainId:s.chainId}):server.NextResponse.json({isLoggedIn:false},{status:401})}let u=async(o,s)=>{let n=(await s.params||{})?.siwe||[],r=n[n.length-1];return r==="login"&&o.method==="POST"?f(o):r==="session"&&o.method==="GET"||r==="logout"&&(o.method==="POST"||o.method==="DELETE")?S(o):Promise.resolve(new Response("Not Found",{status:404}))};return {GET:u,POST:u,DELETE:u}}
|
|
2
2
|
exports.createSiweApiHandler=_;exports.getSessionOptions=l;
|
package/dist/server/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {getIronSession}from'iron-session';import {NextResponse}from'next/server';import {verifyMessage}from'viem';import {parseSiweMessage,validateSiweMessage}from'viem/siwe';function l(t){let e=t.session||{},c=process.env.SIWE_SESSION_SECRET,a=e.password||c;if(!a||a.length<32)throw new Error("SIWE Error: Iron Session requires a 'password' option (min 32 chars) or SIWE_SESSION_SECRET environment variable to be set.");let S={...{secure:process.env.NODE_ENV==="production",maxAge:300*60,httpOnly:true,sameSite:"lax",path:"/"},...e.cookieOptions};return {password:a,cookieName:e.cookieName||"satellite_siwe",cookieOptions:S}}function
|
|
1
|
+
import {getIronSession}from'iron-session';import {NextResponse}from'next/server';import {verifyMessage}from'viem';import {parseSiweMessage,validateSiweMessage}from'viem/siwe';function l(t){let e=t.session||{},c=process.env.SIWE_SESSION_SECRET,a=e.password||c;if(!a||a.length<32)throw new Error("SIWE Error: Iron Session requires a 'password' option (min 32 chars) or SIWE_SESSION_SECRET environment variable to be set.");let S={...{secure:process.env.NODE_ENV==="production",maxAge:300*60,httpOnly:true,sameSite:"lax",path:"/"},...e.cookieOptions};return {password:a,cookieName:e.cookieName||"satellite_siwe",cookieOptions:S}}function L(t){if(!t)return console.warn("SIWE WARN: SIWE_SESSION_URL is not defined. Defaulting domain check to 'localhost'."),"localhost";try{return new URL(t.startsWith("http")?t:`https://${t}`).host}catch(e){return console.error(`SIWE ERROR: Invalid URL provided in SIWE_SESSION_URL: ${t}. Error: ${typeof e=="string"?e:e.message}`),"localhost"}}function _(t={}){let e=t.options||{},c=l(t);async function a(o){let s=new Response;return {session:await getIronSession(o,s,c),response:s}}async function f(o){try{let{message:s,signature:d}=await o.json();if(!s||!d)return NextResponse.json({message:"Missing message or signature"},{status:400});e.afterNonce&&await e.afterNonce();let n=parseSiweMessage(s);if(!n||!n.address||!n.chainId)return NextResponse.json({message:"Invalid SIWE message format"},{status:400});let r=L(process.env.SIWE_SESSION_URL);if(!validateSiweMessage({message:n,domain:r}))return NextResponse.json({message:"SIWE message validation failed"},{status:401});if(!await verifyMessage({address:n.address,message:s,signature:d}))return NextResponse.json({message:"SIWE signature verification failed"},{status:401});e.afterVerify&&await e.afterVerify();let{session:p,response:E}=await a(o);p.address=n.address,p.chainId=n.chainId,p.isLoggedIn=!0,await p.save(),e.afterSession&&await e.afterSession();let m=NextResponse.json({isLoggedIn:!0,address:p.address,chainId:p.chainId},{status:200});return E.headers.forEach((I,w)=>{w.toLowerCase()==="set-cookie"&&m.headers.append("Set-Cookie",I);}),m}catch(s){return console.error("SIWE CRITICAL AUTHENTICATION ERROR:",s),NextResponse.json({message:"Internal Server Error during session validation"},{status:500})}}async function S(o){let{session:s,response:d}=await a(o);if(o.method==="POST"||o.method==="DELETE"){s.destroy(),e.afterLogout&&await e.afterLogout();let n=NextResponse.json({isLoggedIn:false},{status:200});return d.headers.forEach((r,g)=>{g.toLowerCase()==="set-cookie"&&n.headers.append("Set-Cookie",r);}),n}return s.isLoggedIn&&s.address&&s.chainId?NextResponse.json({isLoggedIn:true,address:s.address,chainId:s.chainId}):NextResponse.json({isLoggedIn:false},{status:401})}let u=async(o,s)=>{let n=(await s.params||{})?.siwe||[],r=n[n.length-1];return r==="login"&&o.method==="POST"?f(o):r==="session"&&o.method==="GET"||r==="logout"&&(o.method==="POST"||o.method==="DELETE")?S(o):Promise.resolve(new Response("Not Found",{status:404}))};return {GET:u,POST:u,DELETE:u}}
|
|
2
2
|
export{_ as createSiweApiHandler,l as getSessionOptions};
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tuwaio/satellite-siwe-next-auth",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Oleksandr Tkach",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
|
-
"description": "
|
|
7
|
+
"description": "Robust server-side session authentication adapter mapping cryptographic signatures to the SIWE standard and NextAuth.",
|
|
8
8
|
"main": "./dist/index.js",
|
|
9
9
|
"module": "./dist/index.mjs",
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
@@ -59,15 +59,15 @@
|
|
|
59
59
|
"wagmi": "3.x.x"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@wagmi/core": "^3.
|
|
63
|
-
"@types/react": "^19.2.
|
|
64
|
-
"next": "16.2.
|
|
62
|
+
"@wagmi/core": "^3.5.1",
|
|
63
|
+
"@types/react": "^19.2.17",
|
|
64
|
+
"next": "16.2.9",
|
|
65
65
|
"iron-session": "^8.0.4",
|
|
66
|
-
"react": "^19.2.
|
|
66
|
+
"react": "^19.2.7",
|
|
67
67
|
"tsup": "^8.5.1",
|
|
68
68
|
"typescript": "^6.0.3",
|
|
69
|
-
"viem": "^2.
|
|
70
|
-
"wagmi": "^3.6.
|
|
69
|
+
"viem": "^2.53.1",
|
|
70
|
+
"wagmi": "^3.6.17"
|
|
71
71
|
},
|
|
72
72
|
"scripts": {
|
|
73
73
|
"start": "tsup src/index.ts --watch",
|