@tuwaio/satellite-siwe-next-auth 0.1.1 → 0.2.0
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 +2 -2
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -39,10 +39,10 @@ Built on top of **Wagmi/Viem** for signature generation.
|
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
41
|
# Using pnpm (recommended)
|
|
42
|
-
pnpm add @tuwaio/satellite-siwe-next-auth siwe iron-session wagmi viem
|
|
42
|
+
pnpm add @tuwaio/satellite-siwe-next-auth siwe iron-session wagmi @wagmi/core viem
|
|
43
43
|
|
|
44
44
|
# Using npm
|
|
45
|
-
npm install @tuwaio/satellite-siwe-next-auth siwe iron-session wagmi viem
|
|
45
|
+
npm install @tuwaio/satellite-siwe-next-auth siwe iron-session wagmi @wagmi/core viem
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
### Environment Setup
|
package/dist/index.d.mts
CHANGED
|
@@ -113,7 +113,7 @@ interface SIWESession {
|
|
|
113
113
|
* @interface SiweAuthContextType
|
|
114
114
|
* Interface for the SIWE authentication context state and actions.
|
|
115
115
|
* @property {SIWESession | undefined} data - The authenticated SIWE data (address, chainId) if signed in.
|
|
116
|
-
* @property {boolean} isReadyToSign - True if an EVM
|
|
116
|
+
* @property {boolean} isReadyToSign - True if an EVM connector is connected and ready to sign.
|
|
117
117
|
* @property {boolean} isRejected - True if the last signing attempt was explicitly rejected by the user.
|
|
118
118
|
* @property {boolean} isLoading - True if the session status is loading.
|
|
119
119
|
* @property {boolean} isSignedIn - True if the user has a valid NextAuth session.
|
|
@@ -132,7 +132,7 @@ interface SiweAuthContextType {
|
|
|
132
132
|
}
|
|
133
133
|
/**
|
|
134
134
|
* @interface UseSiweSignatureResult
|
|
135
|
-
* @property {boolean} isReadyToSign - True if an EVM
|
|
135
|
+
* @property {boolean} isReadyToSign - True if an EVM connector is connected and ready to sign.
|
|
136
136
|
* @property {boolean} isRejected - True if the last signing attempt was explicitly rejected by the user.
|
|
137
137
|
* @property {function(GetSiweMessageOptions?): Promise<{message: string, signature: Address} | undefined>} getSiweSignature - Function to generate message and get signature.
|
|
138
138
|
*/
|
|
@@ -149,7 +149,7 @@ interface UseSiweSignatureResult {
|
|
|
149
149
|
* @property {boolean} [enabled=true] - Enables or disables SIWE authentication globally.
|
|
150
150
|
* @property {number} [nonceRefetchInterval=300000] - Interval (ms) for refetching session/nonce token (defaults to 5 mins).
|
|
151
151
|
* @property {(session?: SIWESession) => void} [onSignIn] - Callback executed after a successful SIWE sign-in.
|
|
152
|
-
* @property {() => void} [onSignOut] - Callback executed after a successful sign-out or
|
|
152
|
+
* @property {() => void} [onSignOut] - Callback executed after a successful sign-out or connector disconnect.
|
|
153
153
|
* @property {GetSiweMessageOptions} [getSiweMessageOptions] - Optional function to customize the SIWE message fields.
|
|
154
154
|
* @property {ReactNode} children - Child components.
|
|
155
155
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -113,7 +113,7 @@ interface SIWESession {
|
|
|
113
113
|
* @interface SiweAuthContextType
|
|
114
114
|
* Interface for the SIWE authentication context state and actions.
|
|
115
115
|
* @property {SIWESession | undefined} data - The authenticated SIWE data (address, chainId) if signed in.
|
|
116
|
-
* @property {boolean} isReadyToSign - True if an EVM
|
|
116
|
+
* @property {boolean} isReadyToSign - True if an EVM connector is connected and ready to sign.
|
|
117
117
|
* @property {boolean} isRejected - True if the last signing attempt was explicitly rejected by the user.
|
|
118
118
|
* @property {boolean} isLoading - True if the session status is loading.
|
|
119
119
|
* @property {boolean} isSignedIn - True if the user has a valid NextAuth session.
|
|
@@ -132,7 +132,7 @@ interface SiweAuthContextType {
|
|
|
132
132
|
}
|
|
133
133
|
/**
|
|
134
134
|
* @interface UseSiweSignatureResult
|
|
135
|
-
* @property {boolean} isReadyToSign - True if an EVM
|
|
135
|
+
* @property {boolean} isReadyToSign - True if an EVM connector is connected and ready to sign.
|
|
136
136
|
* @property {boolean} isRejected - True if the last signing attempt was explicitly rejected by the user.
|
|
137
137
|
* @property {function(GetSiweMessageOptions?): Promise<{message: string, signature: Address} | undefined>} getSiweSignature - Function to generate message and get signature.
|
|
138
138
|
*/
|
|
@@ -149,7 +149,7 @@ interface UseSiweSignatureResult {
|
|
|
149
149
|
* @property {boolean} [enabled=true] - Enables or disables SIWE authentication globally.
|
|
150
150
|
* @property {number} [nonceRefetchInterval=300000] - Interval (ms) for refetching session/nonce token (defaults to 5 mins).
|
|
151
151
|
* @property {(session?: SIWESession) => void} [onSignIn] - Callback executed after a successful SIWE sign-in.
|
|
152
|
-
* @property {() => void} [onSignOut] - Callback executed after a successful sign-out or
|
|
152
|
+
* @property {() => void} [onSignOut] - Callback executed after a successful sign-out or connector disconnect.
|
|
153
153
|
* @property {GetSiweMessageOptions} [getSiweMessageOptions] - Optional function to customize the SIWE message fields.
|
|
154
154
|
* @property {ReactNode} children - Child components.
|
|
155
155
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var react=require('react'),core=require('@wagmi/core'),wagmi=require('wagmi'),siwe=require('viem/siwe'),jsxRuntime=require('react/jsx-runtime');function L(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
|
|
1
|
+
'use strict';var react=require('react'),core=require('@wagmi/core'),wagmi=require('wagmi'),siwe=require('viem/siwe'),jsxRuntime=require('react/jsx-runtime');function L(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 A=react.createContext(void 0);function de(t){let e=react.useContext(A);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 k({wagmiConfig:t}){let{isConnected:e,address:r,chainId:a}=wagmi.useConnection({config:t}),[h,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:h}}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:h,getSiweMessageOptions:d}){let[u,p]=react.useState(void 0),[S,n]=react.useState("loading"),{isReadyToSign:o,getSiweSignature:c,isRejected:w}=k({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},[]);L(()=>{g&&F();},r);let m=react.useCallback(async s=>{await fetch("/api/siwe/logout",{method:"POST"}),p(void 0),n("unauthenticated"),h?.(),s?.();},[h]),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})}),f=await l.json();if(!l.ok||f.isLoggedIn!==!0)throw new Error(`Verification error: ${f.message||"Login failed."}`);console.log("SIWE Authentication successful.");let x={address:f.address,chainId:f.chainId};p(x),n("authenticated"),a?.(x),s?.(x);}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,f=v;s&&i&&s!==i||l&&f&&l!==f?(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(),h?.());}},[g,y,v,W,u,m,e,h]),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(A.Provider,{value:e,children:t.children})}exports.SiweAuthContext=A;exports.SiweNextAuthProvider=We;exports.useInterval=L;exports.useSiweAuth=de;exports.useSiweAuthAdapter=O;exports.useSiweSignature=k;//# sourceMappingURL=index.js.map
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useInterval.tsx","../src/provider/SiweAuthContext.tsx","../src/hooks/useSiweAuth.tsx","../src/hooks/useSiweSignature.tsx","../src/hooks/useSiweAuthAdapter.tsx","../src/provider/SiweNextAuthProvider.tsx"],"names":["useInterval","callback","delay","savedCallback","useRef","useEffect","id","SiweAuthContext","createContext","useSiweAuth","options","context","useContext","signInWithSiwe","useCallback","signOutSiwe","useMemo","fetchNonce","useSiweSignature","wagmiConfig","isConnected","address","chainId","useAccount","isRejected","setIsRejected","useState","isReadyToSign","customOptions","walletSnapshot","getAccount","nonce","messageToSign","createSiweMessage","signature","signMessage","disconnect","error","err","fetchSession","res","data","e","useSiweAuthAdapter","enabled","nonceRefetchInterval","providerOnSignIn","providerOnSignOut","getSiweMessageOptions","localSession","setLocalSession","sessionStatus","setSessionStatus","getSiweSignature","isSigningInAfterContextChange","setIsSigningInAfterContextChange","isAuthenticated","isAuthenticating","updateSession","session","status","userOnSignOut","userOnSignIn","signatureData","response","responseBody","finalSession","sessionAddress","currentAddress","sessionChainId","currentChainId","SiweNextAuthProvider","props","siweAuth","jsx"],"mappings":"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","file":"index.js","sourcesContent":["'use client';\n\nimport { useEffect, useRef } from 'react';\n\n/**\n * @function useInterval\n * Creates a stable interval hook safe for client-side execution.\n */\nexport function useInterval(callback: () => void, delay: number | null) {\n const savedCallback = useRef(callback);\n\n useEffect(() => {\n savedCallback.current = callback;\n }, [callback]);\n\n useEffect(() => {\n if (delay !== null && typeof window !== 'undefined' && window.setInterval) {\n // Use window.setInterval and cast the ID to number to satisfy clearInterval's type\n const id = window.setInterval(() => savedCallback.current(), delay);\n return () => window.clearInterval(id);\n }\n }, [delay]);\n}\n","'use client';\n\nimport { createContext } from 'react';\n\nimport { SiweAuthContextType } from '../types';\n\nexport const SiweAuthContext = createContext<SiweAuthContextType | undefined>(undefined);\n","'use client';\n\nimport { useCallback, useContext, useMemo } from 'react';\n\nimport { SiweAuthContext } from '../provider/SiweAuthContext';\nimport { SiweAuthContextType, SIWESession } from '../types';\n\n/**\n * @function useSiweAuth\n * @description Hook to access the SIWE authentication state and methods.\n * @param {object} [options] - Optional callbacks that override provider-level callbacks.\n * @param {(session?: SIWESession) => void} [options.onSignIn] - Callback executed after a successful sign-in.\n * @param {() => void} [options.onSignOut] - Callback executed after a successful sign-out.\n * @returns {SiweAuthContextType}\n * * @example\n * // const { isSignedIn, signInWithSiwe, data, isRejected } = useSiweAuth();\n */\nexport function useSiweAuth(options?: {\n onSignIn?: (session?: SIWESession) => void;\n onSignOut?: () => void;\n}): SiweAuthContextType {\n const context = useContext(SiweAuthContext);\n if (context === undefined) {\n throw new Error('useSiweAuth must be used within a SiweNextAuthProvider');\n }\n\n // Overrides the context's signOutSiwe/signInWithSiwe with local callbacks\n const signInWithSiwe = useCallback(async () => {\n return context.signInWithSiwe(options?.onSignIn);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [context.signInWithSiwe, options?.onSignIn]);\n\n const signOutSiwe = useCallback(async () => {\n return context.signOutSiwe(options?.onSignOut);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [context.signOutSiwe, options?.onSignOut]);\n\n return useMemo(\n () => ({\n ...context,\n signInWithSiwe,\n signOutSiwe,\n }),\n [context, signInWithSiwe, signOutSiwe],\n );\n}\n","'use client';\n\nimport { Config, disconnect, getAccount, signMessage } from '@wagmi/core';\nimport { useEffect, useMemo, useState } from 'react';\nimport { Address } from 'viem';\nimport { createSiweMessage } from 'viem/siwe';\nimport { useAccount } from 'wagmi';\n\nimport { GetSiweMessageOptions, UseSiweSignatureResult } from '../types';\n\n/**\n * @function fetchNonce\n * @description Generates a cryptographically secure, alphanumeric random string to use as the SIWE nonce,\n * satisfying the viem/SIWE requirement (at least 8 chars, alphanumeric).\n * @returns {Promise<string>} The valid alphanumeric nonce string.\n */\nasync function fetchNonce(): Promise<string> {\n // Generate UUID and remove hyphens to create a secure, alphanumeric nonce.\n return crypto.randomUUID().replace(/-/g, '');\n}\n\n/**\n * @function useSiweSignature\n * @description A low-level hook that handles the core SIWE cryptographic flow:\n * getting the nonce, creating the message, and getting the signature using Wagmi/Viem.\n * This is the building block for custom backend authentication.\n * @returns {UseSiweSignatureResult}\n * * @example\n * // const { getSiweSignature, isReadyToSign, isRejected } = useSiweSignature();\n */\nexport function useSiweSignature({ wagmiConfig }: { wagmiConfig: Config }): UseSiweSignatureResult {\n const { isConnected, address, chainId } = useAccount({ config: wagmiConfig });\n const [isRejected, setIsRejected] = useState(false);\n\n const isReadyToSign = useMemo(() => isConnected && !!address && !!chainId, [isConnected, address, chainId]);\n\n // Clear rejected state upon context change\n useEffect(() => {\n if (isReadyToSign) {\n setIsRejected(false);\n }\n }, [isReadyToSign]);\n\n const getSiweSignature = async (customOptions?: GetSiweMessageOptions) => {\n setIsRejected(false); // Reset rejection status at the start of a new attempt\n\n const walletSnapshot = getAccount(wagmiConfig);\n\n if (!walletSnapshot.isConnected || !walletSnapshot.address || !walletSnapshot.chainId) {\n throw new Error('Wallet not connected or connection details are missing from Wagmi snapshot.');\n }\n\n try {\n // Use the corrected fetchNonce\n const nonce = await fetchNonce();\n if (!nonce) throw new Error('Failed to retrieve CSRF token/nonce.');\n\n const messageToSign = createSiweMessage({\n domain: window.location.host,\n statement: 'Sign in with Ethereum to the application.',\n uri: window.location.origin,\n version: '1',\n ...(customOptions ? customOptions() : {}), // Apply custom options\n address: walletSnapshot.address,\n chainId: walletSnapshot.chainId,\n nonce,\n });\n\n const signature = await signMessage(wagmiConfig, { message: messageToSign });\n\n if (!signature) {\n setIsRejected(true); // Set rejected status if signature is null/undefined\n await disconnect(wagmiConfig);\n throw new Error('Message signing cancelled by user or failed.');\n }\n\n return { message: messageToSign, signature: signature as Address };\n } catch (error) {\n await disconnect(wagmiConfig);\n console.error('Error during signature generation:', error);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const err = error as any;\n if (err.name === 'UserRejectedRequestError' || err.code === 4001 || /user rejected/i.test(err.message)) {\n setIsRejected(true);\n }\n throw error;\n }\n };\n\n return { getSiweSignature, isReadyToSign, isRejected };\n}\n","'use client';\n\nimport { disconnect } from '@wagmi/core';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useAccount } from 'wagmi';\n\nimport { SiweAuthContextType, SiweNextAuthProviderProps, SIWESession } from '../types';\nimport { useInterval } from './useInterval';\nimport { useSiweSignature } from './useSiweSignature';\n\ntype SessionStatus = 'loading' | 'authenticated' | 'unauthenticated';\n\n/**\n * @function fetchSession\n * @description Fetches the current session status and data from the server.\n * @returns {Promise<{session: SIWESession | undefined, status: SessionStatus}>}\n */\nasync function fetchSession(): Promise<{ session: SIWESession | undefined; status: SessionStatus }> {\n try {\n const res = await fetch('/api/siwe/session');\n\n if (res.status === 401 || res.status === 404) {\n return { session: undefined, status: 'unauthenticated' };\n }\n\n if (!res.ok) {\n throw new Error('Failed to fetch session data.');\n }\n\n const data = await res.json();\n\n // NOTE: Data structure must match SiweSessionData {isLoggedIn, address, chainId}\n if (data.isLoggedIn && data.address && data.chainId) {\n return {\n session: { address: data.address, chainId: data.chainId },\n status: 'authenticated',\n };\n }\n return { session: undefined, status: 'unauthenticated' };\n } catch (e) {\n console.error('Error fetching session:', e);\n return { session: undefined, status: 'unauthenticated' };\n }\n}\n\n/**\n * @function useSiweAuthAdapter\n * Internal hook containing the core SIWE/Iron Session logic, acting as the authentication adapter.\n * @returns {SiweAuthContextType}\n */\nexport function useSiweAuthAdapter({\n wagmiConfig,\n enabled = true,\n nonceRefetchInterval = 5 * 60 * 1000, // 5 minutes (300,000 ms)\n onSignIn: providerOnSignIn,\n onSignOut: providerOnSignOut,\n getSiweMessageOptions,\n}: SiweNextAuthProviderProps): SiweAuthContextType {\n const [localSession, setLocalSession] = useState<SIWESession | undefined>(undefined);\n const [sessionStatus, setSessionStatus] = useState<SessionStatus>('loading');\n\n const { isReadyToSign, getSiweSignature, isRejected } = useSiweSignature({ wagmiConfig });\n\n const { address, chainId, isConnected } = useAccount({ config: wagmiConfig });\n\n const [isSigningInAfterContextChange, setIsSigningInAfterContextChange] = useState(false);\n\n const isAuthenticated = sessionStatus === 'authenticated';\n const isAuthenticating = sessionStatus === 'loading';\n const data: SIWESession | undefined = localSession;\n\n // --- SESSION REFETCH (equivalent to NextAuth's update) ---\n const updateSession = useCallback(async () => {\n setSessionStatus('loading');\n const { session, status } = await fetchSession();\n setLocalSession(session);\n setSessionStatus(status);\n return session;\n }, []);\n\n // --- NONCE REFETCH LOGIC (Managed by custom interval) ---\n useInterval(() => {\n if (isAuthenticated) {\n updateSession();\n }\n }, nonceRefetchInterval);\n\n /**\n * @async\n * @method signOutSiwe\n * Clears the session by calling the server API.\n */\n const signOutSiwe = useCallback(\n async (userOnSignOut?: () => void) => {\n await fetch('/api/siwe/logout', { method: 'POST' }); // Call your custom logout API\n setLocalSession(undefined);\n setSessionStatus('unauthenticated');\n\n providerOnSignOut?.(); // Execute provider callback\n userOnSignOut?.(); // Execute user callback\n },\n [providerOnSignOut],\n );\n\n /**\n * @async\n * @method signInWithSiwe\n * Executes the full SIWE authentication flow: signature -> verification -> session creation.\n */\n const signInWithSiwe = useCallback(\n async (userOnSignIn?: (session?: SIWESession) => void) => {\n if (!enabled) {\n throw new Error('SIWE is currently disabled via provider configuration.');\n }\n\n setSessionStatus('loading');\n\n try {\n // 1. Get Signature using the low-level hook\n const signatureData = await getSiweSignature(getSiweMessageOptions);\n\n if (!signatureData) {\n setSessionStatus('unauthenticated');\n return;\n }\n\n // 2. Send message and signature to your custom login API\n const response = await fetch('/api/siwe/login', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n message: signatureData.message,\n signature: signatureData.signature,\n }),\n });\n\n const responseBody = await response.json();\n\n if (!response.ok || responseBody.isLoggedIn !== true) {\n throw new Error(`Verification error: ${responseBody.message || 'Login failed.'}`);\n }\n\n console.log('SIWE Authentication successful.');\n\n // 3. Update session locally\n const finalSession: SIWESession = {\n address: responseBody.address,\n chainId: responseBody.chainId,\n };\n\n setLocalSession(finalSession);\n setSessionStatus('authenticated');\n\n // 4. Execute callbacks after successful sign-in\n providerOnSignIn?.(finalSession);\n userOnSignIn?.(finalSession);\n } catch (error) {\n await disconnect(wagmiConfig);\n setSessionStatus('unauthenticated');\n throw new Error(`SIWE Sign-In failed: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n },\n [enabled, getSiweSignature, getSiweMessageOptions, providerOnSignIn, wagmiConfig],\n );\n\n // --- OBLIGATORY SESSION RESET / AUTO-SIGN IN EFFECT ---\n\n useEffect(() => {\n if (isAuthenticated && enabled) {\n const sessionAddress = localSession?.address?.toLowerCase();\n const currentAddress = address?.toLowerCase();\n const sessionChainId = localSession?.chainId;\n const currentChainId = chainId;\n\n const addressChanged = sessionAddress && currentAddress && sessionAddress !== currentAddress;\n const chainChanged = sessionChainId && currentChainId && sessionChainId !== currentChainId;\n const walletDisconnected = !isConnected;\n\n if (addressChanged || chainChanged) {\n console.log('SIWE: Wallet context changed (Address or Chain ID). Initiating re-authentication.');\n\n setIsSigningInAfterContextChange(true);\n\n // 1. OBLIGATORY SIGN OUT for the old session (security)\n signOutSiwe();\n } else if (walletDisconnected) {\n // Handle explicit wallet disconnection: Always sign out.\n console.log('SIWE: Wallet disconnected. Disconnecting session.');\n signOutSiwe();\n providerOnSignOut?.(); // Execute provider callback for disconnect\n }\n }\n }, [isAuthenticated, address, chainId, isConnected, localSession, signOutSiwe, enabled, providerOnSignOut]);\n\n // --- EFFECT TO EXECUTE AUTO SIGN-IN AFTER STATE RESET ---\n useEffect(() => {\n // Triggers when: 1. Flag is set AND 2. Status transitioned to 'unauthenticated'\n if (isSigningInAfterContextChange && sessionStatus === 'unauthenticated' && isReadyToSign && enabled) {\n console.log('SIWE: State reset detected. Attempting automatic sign-in to establish new session.');\n\n setIsSigningInAfterContextChange(false); // Reset flag\n\n // Auto sign-in execution\n signInWithSiwe().catch((e) => {\n throw new Error(\n `SIWE Auto Sign-In failed after context change: ${e instanceof Error ? e.message : 'Unknown error'}`,\n );\n });\n }\n }, [isSigningInAfterContextChange, sessionStatus, isReadyToSign, signInWithSiwe, enabled]);\n\n // --- FINAL EXPORT ---\n\n return useMemo(\n () => ({\n data,\n isReadyToSign,\n isRejected,\n isLoading: isAuthenticating,\n isSignedIn: isAuthenticated,\n signInWithSiwe,\n signOutSiwe,\n enabled,\n }),\n [data, isReadyToSign, isRejected, isAuthenticating, isAuthenticated, signInWithSiwe, signOutSiwe, enabled],\n );\n}\n","'use client';\n\nimport { useSiweAuthAdapter } from '../hooks/useSiweAuthAdapter';\nimport { SiweNextAuthProviderProps } from '../types';\nimport { SiweAuthContext } from './SiweAuthContext';\n\n/**\n * @component\n * @name SiweNextAuthProvider\n * @description Universal Provider for Sign-In with Ethereum (SIWE) using NextAuth.js.\n * This component handles the SIWE authentication logic.\n * It must be nested inside NextAuth's `<SessionProvider>` and your Wagmi Provider.\n * * **Note**: This provider requires the server-side NextAuth configuration to be set up.\n */\nexport function SiweNextAuthProvider(props: SiweNextAuthProviderProps) {\n const siweAuth = useSiweAuthAdapter(props);\n return <SiweAuthContext.Provider value={siweAuth}>{props.children}</SiweAuthContext.Provider>;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useInterval.tsx","../src/provider/SiweAuthContext.tsx","../src/hooks/useSiweAuth.tsx","../src/hooks/useSiweSignature.tsx","../src/hooks/useSiweAuthAdapter.tsx","../src/provider/SiweNextAuthProvider.tsx"],"names":["useInterval","callback","delay","savedCallback","useRef","useEffect","id","SiweAuthContext","createContext","useSiweAuth","options","context","useContext","signInWithSiwe","useCallback","signOutSiwe","useMemo","fetchNonce","useSiweSignature","wagmiConfig","isConnected","address","chainId","useConnection","isRejected","setIsRejected","useState","isReadyToSign","customOptions","walletSnapshot","getConnection","nonce","messageToSign","createSiweMessage","signature","signMessage","disconnect","error","err","fetchSession","res","data","e","useSiweAuthAdapter","enabled","nonceRefetchInterval","providerOnSignIn","providerOnSignOut","getSiweMessageOptions","localSession","setLocalSession","sessionStatus","setSessionStatus","getSiweSignature","isSigningInAfterContextChange","setIsSigningInAfterContextChange","isAuthenticated","isAuthenticating","updateSession","session","status","userOnSignOut","userOnSignIn","signatureData","response","responseBody","finalSession","sessionAddress","currentAddress","sessionChainId","currentChainId","SiweNextAuthProvider","props","siweAuth","jsx"],"mappings":"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","file":"index.js","sourcesContent":["'use client';\n\nimport { useEffect, useRef } from 'react';\n\n/**\n * @function useInterval\n * Creates a stable interval hook safe for client-side execution.\n */\nexport function useInterval(callback: () => void, delay: number | null) {\n const savedCallback = useRef(callback);\n\n useEffect(() => {\n savedCallback.current = callback;\n }, [callback]);\n\n useEffect(() => {\n if (delay !== null && typeof window !== 'undefined' && window.setInterval) {\n // Use window.setInterval and cast the ID to number to satisfy clearInterval's type\n const id = window.setInterval(() => savedCallback.current(), delay);\n return () => window.clearInterval(id);\n }\n }, [delay]);\n}\n","'use client';\n\nimport { createContext } from 'react';\n\nimport { SiweAuthContextType } from '../types';\n\nexport const SiweAuthContext = createContext<SiweAuthContextType | undefined>(undefined);\n","'use client';\n\nimport { useCallback, useContext, useMemo } from 'react';\n\nimport { SiweAuthContext } from '../provider/SiweAuthContext';\nimport { SiweAuthContextType, SIWESession } from '../types';\n\n/**\n * @function useSiweAuth\n * @description Hook to access the SIWE authentication state and methods.\n * @param {object} [options] - Optional callbacks that override provider-level callbacks.\n * @param {(session?: SIWESession) => void} [options.onSignIn] - Callback executed after a successful sign-in.\n * @param {() => void} [options.onSignOut] - Callback executed after a successful sign-out.\n * @returns {SiweAuthContextType}\n * * @example\n * // const { isSignedIn, signInWithSiwe, data, isRejected } = useSiweAuth();\n */\nexport function useSiweAuth(options?: {\n onSignIn?: (session?: SIWESession) => void;\n onSignOut?: () => void;\n}): SiweAuthContextType {\n const context = useContext(SiweAuthContext);\n if (context === undefined) {\n throw new Error('useSiweAuth must be used within a SiweNextAuthProvider');\n }\n\n // Overrides the context's signOutSiwe/signInWithSiwe with local callbacks\n const signInWithSiwe = useCallback(async () => {\n return context.signInWithSiwe(options?.onSignIn);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [context.signInWithSiwe, options?.onSignIn]);\n\n const signOutSiwe = useCallback(async () => {\n return context.signOutSiwe(options?.onSignOut);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [context.signOutSiwe, options?.onSignOut]);\n\n return useMemo(\n () => ({\n ...context,\n signInWithSiwe,\n signOutSiwe,\n }),\n [context, signInWithSiwe, signOutSiwe],\n );\n}\n","'use client';\n\nimport { Config, disconnect, getConnection, signMessage } from '@wagmi/core';\nimport { useEffect, useMemo, useState } from 'react';\nimport { Address } from 'viem';\nimport { createSiweMessage } from 'viem/siwe';\nimport { useConnection } from 'wagmi';\n\nimport { GetSiweMessageOptions, UseSiweSignatureResult } from '../types';\n\n/**\n * @function fetchNonce\n * @description Generates a cryptographically secure, alphanumeric random string to use as the SIWE nonce,\n * satisfying the viem/SIWE requirement (at least 8 chars, alphanumeric).\n * @returns {Promise<string>} The valid alphanumeric nonce string.\n */\nasync function fetchNonce(): Promise<string> {\n // Generate UUID and remove hyphens to create a secure, alphanumeric nonce.\n return crypto.randomUUID().replace(/-/g, '');\n}\n\n/**\n * @function useSiweSignature\n * @description A low-level hook that handles the core SIWE cryptographic flow:\n * getting the nonce, creating the message, and getting the signature using Wagmi/Viem.\n * This is the building block for custom backend authentication.\n * @returns {UseSiweSignatureResult}\n * * @example\n * // const { getSiweSignature, isReadyToSign, isRejected } = useSiweSignature();\n */\nexport function useSiweSignature({ wagmiConfig }: { wagmiConfig: Config }): UseSiweSignatureResult {\n const { isConnected, address, chainId } = useConnection({ config: wagmiConfig });\n const [isRejected, setIsRejected] = useState(false);\n\n const isReadyToSign = useMemo(() => isConnected && !!address && !!chainId, [isConnected, address, chainId]);\n\n // Clear rejected state upon context change\n useEffect(() => {\n if (isReadyToSign) {\n setIsRejected(false);\n }\n }, [isReadyToSign]);\n\n const getSiweSignature = async (customOptions?: GetSiweMessageOptions) => {\n setIsRejected(false); // Reset rejection status at the start of a new attempt\n\n const walletSnapshot = getConnection(wagmiConfig);\n\n if (!walletSnapshot.isConnected || !walletSnapshot.address || !walletSnapshot.chainId) {\n throw new Error('Connector not connected or connection details are missing from Wagmi snapshot.');\n }\n\n try {\n // Use the corrected fetchNonce\n const nonce = await fetchNonce();\n if (!nonce) throw new Error('Failed to retrieve CSRF token/nonce.');\n\n const messageToSign = createSiweMessage({\n domain: window.location.host,\n statement: 'Sign in with Ethereum to the application.',\n uri: window.location.origin,\n version: '1',\n ...(customOptions ? customOptions() : {}), // Apply custom options\n address: walletSnapshot.address,\n chainId: walletSnapshot.chainId,\n nonce,\n });\n\n const signature = await signMessage(wagmiConfig, { message: messageToSign });\n\n if (!signature) {\n setIsRejected(true); // Set rejected status if signature is null/undefined\n await disconnect(wagmiConfig);\n throw new Error('Message signing cancelled by user or failed.');\n }\n\n return { message: messageToSign, signature: signature as Address };\n } catch (error) {\n await disconnect(wagmiConfig);\n console.error('Error during signature generation:', error);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const err = error as any;\n if (err.name === 'UserRejectedRequestError' || err.code === 4001 || /user rejected/i.test(err.message)) {\n setIsRejected(true);\n }\n throw error;\n }\n };\n\n return { getSiweSignature, isReadyToSign, isRejected };\n}\n","'use client';\n\nimport { disconnect } from '@wagmi/core';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useConnection } from 'wagmi';\n\nimport { SiweAuthContextType, SiweNextAuthProviderProps, SIWESession } from '../types';\nimport { useInterval } from './useInterval';\nimport { useSiweSignature } from './useSiweSignature';\n\ntype SessionStatus = 'loading' | 'authenticated' | 'unauthenticated';\n\n/**\n * @function fetchSession\n * @description Fetches the current session status and data from the server.\n * @returns {Promise<{session: SIWESession | undefined, status: SessionStatus}>}\n */\nasync function fetchSession(): Promise<{ session: SIWESession | undefined; status: SessionStatus }> {\n try {\n const res = await fetch('/api/siwe/session');\n\n if (res.status === 401 || res.status === 404) {\n return { session: undefined, status: 'unauthenticated' };\n }\n\n if (!res.ok) {\n throw new Error('Failed to fetch session data.');\n }\n\n const data = await res.json();\n\n // NOTE: Data structure must match SiweSessionData {isLoggedIn, address, chainId}\n if (data.isLoggedIn && data.address && data.chainId) {\n return {\n session: { address: data.address, chainId: data.chainId },\n status: 'authenticated',\n };\n }\n return { session: undefined, status: 'unauthenticated' };\n } catch (e) {\n console.error('Error fetching session:', e);\n return { session: undefined, status: 'unauthenticated' };\n }\n}\n\n/**\n * @function useSiweAuthAdapter\n * Internal hook containing the core SIWE/Iron Session logic, acting as the authentication adapter.\n * @returns {SiweAuthContextType}\n */\nexport function useSiweAuthAdapter({\n wagmiConfig,\n enabled = true,\n nonceRefetchInterval = 5 * 60 * 1000, // 5 minutes (300,000 ms)\n onSignIn: providerOnSignIn,\n onSignOut: providerOnSignOut,\n getSiweMessageOptions,\n}: SiweNextAuthProviderProps): SiweAuthContextType {\n const [localSession, setLocalSession] = useState<SIWESession | undefined>(undefined);\n const [sessionStatus, setSessionStatus] = useState<SessionStatus>('loading');\n\n const { isReadyToSign, getSiweSignature, isRejected } = useSiweSignature({ wagmiConfig });\n\n const { address, chainId, isConnected } = useConnection({ config: wagmiConfig });\n\n const [isSigningInAfterContextChange, setIsSigningInAfterContextChange] = useState(false);\n\n const isAuthenticated = sessionStatus === 'authenticated';\n const isAuthenticating = sessionStatus === 'loading';\n const data: SIWESession | undefined = localSession;\n\n // --- SESSION REFETCH (equivalent to NextAuth's update) ---\n const updateSession = useCallback(async () => {\n setSessionStatus('loading');\n const { session, status } = await fetchSession();\n setLocalSession(session);\n setSessionStatus(status);\n return session;\n }, []);\n\n // --- NONCE REFETCH LOGIC (Managed by custom interval) ---\n useInterval(() => {\n if (isAuthenticated) {\n updateSession();\n }\n }, nonceRefetchInterval);\n\n /**\n * @async\n * @method signOutSiwe\n * Clears the session by calling the server API.\n */\n const signOutSiwe = useCallback(\n async (userOnSignOut?: () => void) => {\n await fetch('/api/siwe/logout', { method: 'POST' }); // Call your custom logout API\n setLocalSession(undefined);\n setSessionStatus('unauthenticated');\n\n providerOnSignOut?.(); // Execute provider callback\n userOnSignOut?.(); // Execute user callback\n },\n [providerOnSignOut],\n );\n\n /**\n * @async\n * @method signInWithSiwe\n * Executes the full SIWE authentication flow: signature -> verification -> session creation.\n */\n const signInWithSiwe = useCallback(\n async (userOnSignIn?: (session?: SIWESession) => void) => {\n if (!enabled) {\n throw new Error('SIWE is currently disabled via provider configuration.');\n }\n\n setSessionStatus('loading');\n\n try {\n // 1. Get Signature using the low-level hook\n const signatureData = await getSiweSignature(getSiweMessageOptions);\n\n if (!signatureData) {\n setSessionStatus('unauthenticated');\n return;\n }\n\n // 2. Send message and signature to your custom login API\n const response = await fetch('/api/siwe/login', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n message: signatureData.message,\n signature: signatureData.signature,\n }),\n });\n\n const responseBody = await response.json();\n\n if (!response.ok || responseBody.isLoggedIn !== true) {\n throw new Error(`Verification error: ${responseBody.message || 'Login failed.'}`);\n }\n\n console.log('SIWE Authentication successful.');\n\n // 3. Update session locally\n const finalSession: SIWESession = {\n address: responseBody.address,\n chainId: responseBody.chainId,\n };\n\n setLocalSession(finalSession);\n setSessionStatus('authenticated');\n\n // 4. Execute callbacks after successful sign-in\n providerOnSignIn?.(finalSession);\n userOnSignIn?.(finalSession);\n } catch (error) {\n await disconnect(wagmiConfig);\n setSessionStatus('unauthenticated');\n throw new Error(`SIWE Sign-In failed: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n },\n [enabled, getSiweSignature, getSiweMessageOptions, providerOnSignIn, wagmiConfig],\n );\n\n // --- OBLIGATORY SESSION RESET / AUTO-SIGN IN EFFECT ---\n\n useEffect(() => {\n if (isAuthenticated && enabled) {\n const sessionAddress = localSession?.address?.toLowerCase();\n const currentAddress = address?.toLowerCase();\n const sessionChainId = localSession?.chainId;\n const currentChainId = chainId;\n\n const addressChanged = sessionAddress && currentAddress && sessionAddress !== currentAddress;\n const chainChanged = sessionChainId && currentChainId && sessionChainId !== currentChainId;\n const walletDisconnected = !isConnected;\n\n if (addressChanged || chainChanged) {\n console.log('SIWE: Connector context changed (Address or Chain ID). Initiating re-authentication.');\n\n setIsSigningInAfterContextChange(true);\n\n // 1. OBLIGATORY SIGN OUT for the old session (security)\n signOutSiwe();\n } else if (walletDisconnected) {\n // Handle explicit connector disconnection: Always sign out.\n console.log('SIWE: Connector disconnected. Disconnecting session.');\n signOutSiwe();\n providerOnSignOut?.(); // Execute provider callback for disconnect\n }\n }\n }, [isAuthenticated, address, chainId, isConnected, localSession, signOutSiwe, enabled, providerOnSignOut]);\n\n // --- EFFECT TO EXECUTE AUTO SIGN-IN AFTER STATE RESET ---\n useEffect(() => {\n // Triggers when: 1. Flag is set AND 2. Status transitioned to 'unauthenticated'\n if (isSigningInAfterContextChange && sessionStatus === 'unauthenticated' && isReadyToSign && enabled) {\n console.log('SIWE: State reset detected. Attempting automatic sign-in to establish new session.');\n\n setIsSigningInAfterContextChange(false); // Reset flag\n\n // Auto sign-in execution\n signInWithSiwe().catch((e) => {\n throw new Error(\n `SIWE Auto Sign-In failed after context change: ${e instanceof Error ? e.message : 'Unknown error'}`,\n );\n });\n }\n }, [isSigningInAfterContextChange, sessionStatus, isReadyToSign, signInWithSiwe, enabled]);\n\n // --- FINAL EXPORT ---\n\n return useMemo(\n () => ({\n data,\n isReadyToSign,\n isRejected,\n isLoading: isAuthenticating,\n isSignedIn: isAuthenticated,\n signInWithSiwe,\n signOutSiwe,\n enabled,\n }),\n [data, isReadyToSign, isRejected, isAuthenticating, isAuthenticated, signInWithSiwe, signOutSiwe, enabled],\n );\n}\n","'use client';\n\nimport { useSiweAuthAdapter } from '../hooks/useSiweAuthAdapter';\nimport { SiweNextAuthProviderProps } from '../types';\nimport { SiweAuthContext } from './SiweAuthContext';\n\n/**\n * @component\n * @name SiweNextAuthProvider\n * @description Universal Provider for Sign-In with Ethereum (SIWE) using NextAuth.js.\n * This component handles the SIWE authentication logic.\n * It must be nested inside NextAuth's `<SessionProvider>` and your Wagmi Provider.\n * * **Note**: This provider requires the server-side NextAuth configuration to be set up.\n */\nexport function SiweNextAuthProvider(props: SiweNextAuthProviderProps) {\n const siweAuth = useSiweAuthAdapter(props);\n return <SiweAuthContext.Provider value={siweAuth}>{props.children}</SiweAuthContext.Provider>;\n}\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {createContext,useRef,useEffect,useContext,useCallback,useMemo,useState}from'react';import {
|
|
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 L(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 A=createContext(void 0);function de(t){let e=useContext(A);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 k({wagmiConfig:t}){let{isConnected:e,address:r,chainId:a}=useConnection({config:t}),[h,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:h}}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:h,getSiweMessageOptions:d}){let[u,p]=useState(void 0),[S,n]=useState("loading"),{isReadyToSign:o,getSiweSignature:c,isRejected:w}=k({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},[]);L(()=>{g&&F();},r);let m=useCallback(async s=>{await fetch("/api/siwe/logout",{method:"POST"}),p(void 0),n("unauthenticated"),h?.(),s?.();},[h]),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})}),f=await l.json();if(!l.ok||f.isLoggedIn!==!0)throw new Error(`Verification error: ${f.message||"Login failed."}`);console.log("SIWE Authentication successful.");let x={address:f.address,chainId:f.chainId};p(x),n("authenticated"),a?.(x),s?.(x);}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,f=v;s&&i&&s!==i||l&&f&&l!==f?(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(),h?.());}},[g,y,v,W,u,m,e,h]),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(A.Provider,{value:e,children:t.children})}export{A as SiweAuthContext,We as SiweNextAuthProvider,L as useInterval,de as useSiweAuth,O as useSiweAuthAdapter,k as useSiweSignature};//# sourceMappingURL=index.mjs.map
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useInterval.tsx","../src/provider/SiweAuthContext.tsx","../src/hooks/useSiweAuth.tsx","../src/hooks/useSiweSignature.tsx","../src/hooks/useSiweAuthAdapter.tsx","../src/provider/SiweNextAuthProvider.tsx"],"names":["useInterval","callback","delay","savedCallback","useRef","useEffect","id","SiweAuthContext","createContext","useSiweAuth","options","context","useContext","signInWithSiwe","useCallback","signOutSiwe","useMemo","fetchNonce","useSiweSignature","wagmiConfig","isConnected","address","chainId","useAccount","isRejected","setIsRejected","useState","isReadyToSign","customOptions","walletSnapshot","getAccount","nonce","messageToSign","createSiweMessage","signature","signMessage","disconnect","error","err","fetchSession","res","data","e","useSiweAuthAdapter","enabled","nonceRefetchInterval","providerOnSignIn","providerOnSignOut","getSiweMessageOptions","localSession","setLocalSession","sessionStatus","setSessionStatus","getSiweSignature","isSigningInAfterContextChange","setIsSigningInAfterContextChange","isAuthenticated","isAuthenticating","updateSession","session","status","userOnSignOut","userOnSignIn","signatureData","response","responseBody","finalSession","sessionAddress","currentAddress","sessionChainId","currentChainId","SiweNextAuthProvider","props","siweAuth","jsx"],"mappings":"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","file":"index.mjs","sourcesContent":["'use client';\n\nimport { useEffect, useRef } from 'react';\n\n/**\n * @function useInterval\n * Creates a stable interval hook safe for client-side execution.\n */\nexport function useInterval(callback: () => void, delay: number | null) {\n const savedCallback = useRef(callback);\n\n useEffect(() => {\n savedCallback.current = callback;\n }, [callback]);\n\n useEffect(() => {\n if (delay !== null && typeof window !== 'undefined' && window.setInterval) {\n // Use window.setInterval and cast the ID to number to satisfy clearInterval's type\n const id = window.setInterval(() => savedCallback.current(), delay);\n return () => window.clearInterval(id);\n }\n }, [delay]);\n}\n","'use client';\n\nimport { createContext } from 'react';\n\nimport { SiweAuthContextType } from '../types';\n\nexport const SiweAuthContext = createContext<SiweAuthContextType | undefined>(undefined);\n","'use client';\n\nimport { useCallback, useContext, useMemo } from 'react';\n\nimport { SiweAuthContext } from '../provider/SiweAuthContext';\nimport { SiweAuthContextType, SIWESession } from '../types';\n\n/**\n * @function useSiweAuth\n * @description Hook to access the SIWE authentication state and methods.\n * @param {object} [options] - Optional callbacks that override provider-level callbacks.\n * @param {(session?: SIWESession) => void} [options.onSignIn] - Callback executed after a successful sign-in.\n * @param {() => void} [options.onSignOut] - Callback executed after a successful sign-out.\n * @returns {SiweAuthContextType}\n * * @example\n * // const { isSignedIn, signInWithSiwe, data, isRejected } = useSiweAuth();\n */\nexport function useSiweAuth(options?: {\n onSignIn?: (session?: SIWESession) => void;\n onSignOut?: () => void;\n}): SiweAuthContextType {\n const context = useContext(SiweAuthContext);\n if (context === undefined) {\n throw new Error('useSiweAuth must be used within a SiweNextAuthProvider');\n }\n\n // Overrides the context's signOutSiwe/signInWithSiwe with local callbacks\n const signInWithSiwe = useCallback(async () => {\n return context.signInWithSiwe(options?.onSignIn);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [context.signInWithSiwe, options?.onSignIn]);\n\n const signOutSiwe = useCallback(async () => {\n return context.signOutSiwe(options?.onSignOut);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [context.signOutSiwe, options?.onSignOut]);\n\n return useMemo(\n () => ({\n ...context,\n signInWithSiwe,\n signOutSiwe,\n }),\n [context, signInWithSiwe, signOutSiwe],\n );\n}\n","'use client';\n\nimport { Config, disconnect, getAccount, signMessage } from '@wagmi/core';\nimport { useEffect, useMemo, useState } from 'react';\nimport { Address } from 'viem';\nimport { createSiweMessage } from 'viem/siwe';\nimport { useAccount } from 'wagmi';\n\nimport { GetSiweMessageOptions, UseSiweSignatureResult } from '../types';\n\n/**\n * @function fetchNonce\n * @description Generates a cryptographically secure, alphanumeric random string to use as the SIWE nonce,\n * satisfying the viem/SIWE requirement (at least 8 chars, alphanumeric).\n * @returns {Promise<string>} The valid alphanumeric nonce string.\n */\nasync function fetchNonce(): Promise<string> {\n // Generate UUID and remove hyphens to create a secure, alphanumeric nonce.\n return crypto.randomUUID().replace(/-/g, '');\n}\n\n/**\n * @function useSiweSignature\n * @description A low-level hook that handles the core SIWE cryptographic flow:\n * getting the nonce, creating the message, and getting the signature using Wagmi/Viem.\n * This is the building block for custom backend authentication.\n * @returns {UseSiweSignatureResult}\n * * @example\n * // const { getSiweSignature, isReadyToSign, isRejected } = useSiweSignature();\n */\nexport function useSiweSignature({ wagmiConfig }: { wagmiConfig: Config }): UseSiweSignatureResult {\n const { isConnected, address, chainId } = useAccount({ config: wagmiConfig });\n const [isRejected, setIsRejected] = useState(false);\n\n const isReadyToSign = useMemo(() => isConnected && !!address && !!chainId, [isConnected, address, chainId]);\n\n // Clear rejected state upon context change\n useEffect(() => {\n if (isReadyToSign) {\n setIsRejected(false);\n }\n }, [isReadyToSign]);\n\n const getSiweSignature = async (customOptions?: GetSiweMessageOptions) => {\n setIsRejected(false); // Reset rejection status at the start of a new attempt\n\n const walletSnapshot = getAccount(wagmiConfig);\n\n if (!walletSnapshot.isConnected || !walletSnapshot.address || !walletSnapshot.chainId) {\n throw new Error('Wallet not connected or connection details are missing from Wagmi snapshot.');\n }\n\n try {\n // Use the corrected fetchNonce\n const nonce = await fetchNonce();\n if (!nonce) throw new Error('Failed to retrieve CSRF token/nonce.');\n\n const messageToSign = createSiweMessage({\n domain: window.location.host,\n statement: 'Sign in with Ethereum to the application.',\n uri: window.location.origin,\n version: '1',\n ...(customOptions ? customOptions() : {}), // Apply custom options\n address: walletSnapshot.address,\n chainId: walletSnapshot.chainId,\n nonce,\n });\n\n const signature = await signMessage(wagmiConfig, { message: messageToSign });\n\n if (!signature) {\n setIsRejected(true); // Set rejected status if signature is null/undefined\n await disconnect(wagmiConfig);\n throw new Error('Message signing cancelled by user or failed.');\n }\n\n return { message: messageToSign, signature: signature as Address };\n } catch (error) {\n await disconnect(wagmiConfig);\n console.error('Error during signature generation:', error);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const err = error as any;\n if (err.name === 'UserRejectedRequestError' || err.code === 4001 || /user rejected/i.test(err.message)) {\n setIsRejected(true);\n }\n throw error;\n }\n };\n\n return { getSiweSignature, isReadyToSign, isRejected };\n}\n","'use client';\n\nimport { disconnect } from '@wagmi/core';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useAccount } from 'wagmi';\n\nimport { SiweAuthContextType, SiweNextAuthProviderProps, SIWESession } from '../types';\nimport { useInterval } from './useInterval';\nimport { useSiweSignature } from './useSiweSignature';\n\ntype SessionStatus = 'loading' | 'authenticated' | 'unauthenticated';\n\n/**\n * @function fetchSession\n * @description Fetches the current session status and data from the server.\n * @returns {Promise<{session: SIWESession | undefined, status: SessionStatus}>}\n */\nasync function fetchSession(): Promise<{ session: SIWESession | undefined; status: SessionStatus }> {\n try {\n const res = await fetch('/api/siwe/session');\n\n if (res.status === 401 || res.status === 404) {\n return { session: undefined, status: 'unauthenticated' };\n }\n\n if (!res.ok) {\n throw new Error('Failed to fetch session data.');\n }\n\n const data = await res.json();\n\n // NOTE: Data structure must match SiweSessionData {isLoggedIn, address, chainId}\n if (data.isLoggedIn && data.address && data.chainId) {\n return {\n session: { address: data.address, chainId: data.chainId },\n status: 'authenticated',\n };\n }\n return { session: undefined, status: 'unauthenticated' };\n } catch (e) {\n console.error('Error fetching session:', e);\n return { session: undefined, status: 'unauthenticated' };\n }\n}\n\n/**\n * @function useSiweAuthAdapter\n * Internal hook containing the core SIWE/Iron Session logic, acting as the authentication adapter.\n * @returns {SiweAuthContextType}\n */\nexport function useSiweAuthAdapter({\n wagmiConfig,\n enabled = true,\n nonceRefetchInterval = 5 * 60 * 1000, // 5 minutes (300,000 ms)\n onSignIn: providerOnSignIn,\n onSignOut: providerOnSignOut,\n getSiweMessageOptions,\n}: SiweNextAuthProviderProps): SiweAuthContextType {\n const [localSession, setLocalSession] = useState<SIWESession | undefined>(undefined);\n const [sessionStatus, setSessionStatus] = useState<SessionStatus>('loading');\n\n const { isReadyToSign, getSiweSignature, isRejected } = useSiweSignature({ wagmiConfig });\n\n const { address, chainId, isConnected } = useAccount({ config: wagmiConfig });\n\n const [isSigningInAfterContextChange, setIsSigningInAfterContextChange] = useState(false);\n\n const isAuthenticated = sessionStatus === 'authenticated';\n const isAuthenticating = sessionStatus === 'loading';\n const data: SIWESession | undefined = localSession;\n\n // --- SESSION REFETCH (equivalent to NextAuth's update) ---\n const updateSession = useCallback(async () => {\n setSessionStatus('loading');\n const { session, status } = await fetchSession();\n setLocalSession(session);\n setSessionStatus(status);\n return session;\n }, []);\n\n // --- NONCE REFETCH LOGIC (Managed by custom interval) ---\n useInterval(() => {\n if (isAuthenticated) {\n updateSession();\n }\n }, nonceRefetchInterval);\n\n /**\n * @async\n * @method signOutSiwe\n * Clears the session by calling the server API.\n */\n const signOutSiwe = useCallback(\n async (userOnSignOut?: () => void) => {\n await fetch('/api/siwe/logout', { method: 'POST' }); // Call your custom logout API\n setLocalSession(undefined);\n setSessionStatus('unauthenticated');\n\n providerOnSignOut?.(); // Execute provider callback\n userOnSignOut?.(); // Execute user callback\n },\n [providerOnSignOut],\n );\n\n /**\n * @async\n * @method signInWithSiwe\n * Executes the full SIWE authentication flow: signature -> verification -> session creation.\n */\n const signInWithSiwe = useCallback(\n async (userOnSignIn?: (session?: SIWESession) => void) => {\n if (!enabled) {\n throw new Error('SIWE is currently disabled via provider configuration.');\n }\n\n setSessionStatus('loading');\n\n try {\n // 1. Get Signature using the low-level hook\n const signatureData = await getSiweSignature(getSiweMessageOptions);\n\n if (!signatureData) {\n setSessionStatus('unauthenticated');\n return;\n }\n\n // 2. Send message and signature to your custom login API\n const response = await fetch('/api/siwe/login', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n message: signatureData.message,\n signature: signatureData.signature,\n }),\n });\n\n const responseBody = await response.json();\n\n if (!response.ok || responseBody.isLoggedIn !== true) {\n throw new Error(`Verification error: ${responseBody.message || 'Login failed.'}`);\n }\n\n console.log('SIWE Authentication successful.');\n\n // 3. Update session locally\n const finalSession: SIWESession = {\n address: responseBody.address,\n chainId: responseBody.chainId,\n };\n\n setLocalSession(finalSession);\n setSessionStatus('authenticated');\n\n // 4. Execute callbacks after successful sign-in\n providerOnSignIn?.(finalSession);\n userOnSignIn?.(finalSession);\n } catch (error) {\n await disconnect(wagmiConfig);\n setSessionStatus('unauthenticated');\n throw new Error(`SIWE Sign-In failed: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n },\n [enabled, getSiweSignature, getSiweMessageOptions, providerOnSignIn, wagmiConfig],\n );\n\n // --- OBLIGATORY SESSION RESET / AUTO-SIGN IN EFFECT ---\n\n useEffect(() => {\n if (isAuthenticated && enabled) {\n const sessionAddress = localSession?.address?.toLowerCase();\n const currentAddress = address?.toLowerCase();\n const sessionChainId = localSession?.chainId;\n const currentChainId = chainId;\n\n const addressChanged = sessionAddress && currentAddress && sessionAddress !== currentAddress;\n const chainChanged = sessionChainId && currentChainId && sessionChainId !== currentChainId;\n const walletDisconnected = !isConnected;\n\n if (addressChanged || chainChanged) {\n console.log('SIWE: Wallet context changed (Address or Chain ID). Initiating re-authentication.');\n\n setIsSigningInAfterContextChange(true);\n\n // 1. OBLIGATORY SIGN OUT for the old session (security)\n signOutSiwe();\n } else if (walletDisconnected) {\n // Handle explicit wallet disconnection: Always sign out.\n console.log('SIWE: Wallet disconnected. Disconnecting session.');\n signOutSiwe();\n providerOnSignOut?.(); // Execute provider callback for disconnect\n }\n }\n }, [isAuthenticated, address, chainId, isConnected, localSession, signOutSiwe, enabled, providerOnSignOut]);\n\n // --- EFFECT TO EXECUTE AUTO SIGN-IN AFTER STATE RESET ---\n useEffect(() => {\n // Triggers when: 1. Flag is set AND 2. Status transitioned to 'unauthenticated'\n if (isSigningInAfterContextChange && sessionStatus === 'unauthenticated' && isReadyToSign && enabled) {\n console.log('SIWE: State reset detected. Attempting automatic sign-in to establish new session.');\n\n setIsSigningInAfterContextChange(false); // Reset flag\n\n // Auto sign-in execution\n signInWithSiwe().catch((e) => {\n throw new Error(\n `SIWE Auto Sign-In failed after context change: ${e instanceof Error ? e.message : 'Unknown error'}`,\n );\n });\n }\n }, [isSigningInAfterContextChange, sessionStatus, isReadyToSign, signInWithSiwe, enabled]);\n\n // --- FINAL EXPORT ---\n\n return useMemo(\n () => ({\n data,\n isReadyToSign,\n isRejected,\n isLoading: isAuthenticating,\n isSignedIn: isAuthenticated,\n signInWithSiwe,\n signOutSiwe,\n enabled,\n }),\n [data, isReadyToSign, isRejected, isAuthenticating, isAuthenticated, signInWithSiwe, signOutSiwe, enabled],\n );\n}\n","'use client';\n\nimport { useSiweAuthAdapter } from '../hooks/useSiweAuthAdapter';\nimport { SiweNextAuthProviderProps } from '../types';\nimport { SiweAuthContext } from './SiweAuthContext';\n\n/**\n * @component\n * @name SiweNextAuthProvider\n * @description Universal Provider for Sign-In with Ethereum (SIWE) using NextAuth.js.\n * This component handles the SIWE authentication logic.\n * It must be nested inside NextAuth's `<SessionProvider>` and your Wagmi Provider.\n * * **Note**: This provider requires the server-side NextAuth configuration to be set up.\n */\nexport function SiweNextAuthProvider(props: SiweNextAuthProviderProps) {\n const siweAuth = useSiweAuthAdapter(props);\n return <SiweAuthContext.Provider value={siweAuth}>{props.children}</SiweAuthContext.Provider>;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useInterval.tsx","../src/provider/SiweAuthContext.tsx","../src/hooks/useSiweAuth.tsx","../src/hooks/useSiweSignature.tsx","../src/hooks/useSiweAuthAdapter.tsx","../src/provider/SiweNextAuthProvider.tsx"],"names":["useInterval","callback","delay","savedCallback","useRef","useEffect","id","SiweAuthContext","createContext","useSiweAuth","options","context","useContext","signInWithSiwe","useCallback","signOutSiwe","useMemo","fetchNonce","useSiweSignature","wagmiConfig","isConnected","address","chainId","useConnection","isRejected","setIsRejected","useState","isReadyToSign","customOptions","walletSnapshot","getConnection","nonce","messageToSign","createSiweMessage","signature","signMessage","disconnect","error","err","fetchSession","res","data","e","useSiweAuthAdapter","enabled","nonceRefetchInterval","providerOnSignIn","providerOnSignOut","getSiweMessageOptions","localSession","setLocalSession","sessionStatus","setSessionStatus","getSiweSignature","isSigningInAfterContextChange","setIsSigningInAfterContextChange","isAuthenticated","isAuthenticating","updateSession","session","status","userOnSignOut","userOnSignIn","signatureData","response","responseBody","finalSession","sessionAddress","currentAddress","sessionChainId","currentChainId","SiweNextAuthProvider","props","siweAuth","jsx"],"mappings":"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","file":"index.mjs","sourcesContent":["'use client';\n\nimport { useEffect, useRef } from 'react';\n\n/**\n * @function useInterval\n * Creates a stable interval hook safe for client-side execution.\n */\nexport function useInterval(callback: () => void, delay: number | null) {\n const savedCallback = useRef(callback);\n\n useEffect(() => {\n savedCallback.current = callback;\n }, [callback]);\n\n useEffect(() => {\n if (delay !== null && typeof window !== 'undefined' && window.setInterval) {\n // Use window.setInterval and cast the ID to number to satisfy clearInterval's type\n const id = window.setInterval(() => savedCallback.current(), delay);\n return () => window.clearInterval(id);\n }\n }, [delay]);\n}\n","'use client';\n\nimport { createContext } from 'react';\n\nimport { SiweAuthContextType } from '../types';\n\nexport const SiweAuthContext = createContext<SiweAuthContextType | undefined>(undefined);\n","'use client';\n\nimport { useCallback, useContext, useMemo } from 'react';\n\nimport { SiweAuthContext } from '../provider/SiweAuthContext';\nimport { SiweAuthContextType, SIWESession } from '../types';\n\n/**\n * @function useSiweAuth\n * @description Hook to access the SIWE authentication state and methods.\n * @param {object} [options] - Optional callbacks that override provider-level callbacks.\n * @param {(session?: SIWESession) => void} [options.onSignIn] - Callback executed after a successful sign-in.\n * @param {() => void} [options.onSignOut] - Callback executed after a successful sign-out.\n * @returns {SiweAuthContextType}\n * * @example\n * // const { isSignedIn, signInWithSiwe, data, isRejected } = useSiweAuth();\n */\nexport function useSiweAuth(options?: {\n onSignIn?: (session?: SIWESession) => void;\n onSignOut?: () => void;\n}): SiweAuthContextType {\n const context = useContext(SiweAuthContext);\n if (context === undefined) {\n throw new Error('useSiweAuth must be used within a SiweNextAuthProvider');\n }\n\n // Overrides the context's signOutSiwe/signInWithSiwe with local callbacks\n const signInWithSiwe = useCallback(async () => {\n return context.signInWithSiwe(options?.onSignIn);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [context.signInWithSiwe, options?.onSignIn]);\n\n const signOutSiwe = useCallback(async () => {\n return context.signOutSiwe(options?.onSignOut);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [context.signOutSiwe, options?.onSignOut]);\n\n return useMemo(\n () => ({\n ...context,\n signInWithSiwe,\n signOutSiwe,\n }),\n [context, signInWithSiwe, signOutSiwe],\n );\n}\n","'use client';\n\nimport { Config, disconnect, getConnection, signMessage } from '@wagmi/core';\nimport { useEffect, useMemo, useState } from 'react';\nimport { Address } from 'viem';\nimport { createSiweMessage } from 'viem/siwe';\nimport { useConnection } from 'wagmi';\n\nimport { GetSiweMessageOptions, UseSiweSignatureResult } from '../types';\n\n/**\n * @function fetchNonce\n * @description Generates a cryptographically secure, alphanumeric random string to use as the SIWE nonce,\n * satisfying the viem/SIWE requirement (at least 8 chars, alphanumeric).\n * @returns {Promise<string>} The valid alphanumeric nonce string.\n */\nasync function fetchNonce(): Promise<string> {\n // Generate UUID and remove hyphens to create a secure, alphanumeric nonce.\n return crypto.randomUUID().replace(/-/g, '');\n}\n\n/**\n * @function useSiweSignature\n * @description A low-level hook that handles the core SIWE cryptographic flow:\n * getting the nonce, creating the message, and getting the signature using Wagmi/Viem.\n * This is the building block for custom backend authentication.\n * @returns {UseSiweSignatureResult}\n * * @example\n * // const { getSiweSignature, isReadyToSign, isRejected } = useSiweSignature();\n */\nexport function useSiweSignature({ wagmiConfig }: { wagmiConfig: Config }): UseSiweSignatureResult {\n const { isConnected, address, chainId } = useConnection({ config: wagmiConfig });\n const [isRejected, setIsRejected] = useState(false);\n\n const isReadyToSign = useMemo(() => isConnected && !!address && !!chainId, [isConnected, address, chainId]);\n\n // Clear rejected state upon context change\n useEffect(() => {\n if (isReadyToSign) {\n setIsRejected(false);\n }\n }, [isReadyToSign]);\n\n const getSiweSignature = async (customOptions?: GetSiweMessageOptions) => {\n setIsRejected(false); // Reset rejection status at the start of a new attempt\n\n const walletSnapshot = getConnection(wagmiConfig);\n\n if (!walletSnapshot.isConnected || !walletSnapshot.address || !walletSnapshot.chainId) {\n throw new Error('Connector not connected or connection details are missing from Wagmi snapshot.');\n }\n\n try {\n // Use the corrected fetchNonce\n const nonce = await fetchNonce();\n if (!nonce) throw new Error('Failed to retrieve CSRF token/nonce.');\n\n const messageToSign = createSiweMessage({\n domain: window.location.host,\n statement: 'Sign in with Ethereum to the application.',\n uri: window.location.origin,\n version: '1',\n ...(customOptions ? customOptions() : {}), // Apply custom options\n address: walletSnapshot.address,\n chainId: walletSnapshot.chainId,\n nonce,\n });\n\n const signature = await signMessage(wagmiConfig, { message: messageToSign });\n\n if (!signature) {\n setIsRejected(true); // Set rejected status if signature is null/undefined\n await disconnect(wagmiConfig);\n throw new Error('Message signing cancelled by user or failed.');\n }\n\n return { message: messageToSign, signature: signature as Address };\n } catch (error) {\n await disconnect(wagmiConfig);\n console.error('Error during signature generation:', error);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const err = error as any;\n if (err.name === 'UserRejectedRequestError' || err.code === 4001 || /user rejected/i.test(err.message)) {\n setIsRejected(true);\n }\n throw error;\n }\n };\n\n return { getSiweSignature, isReadyToSign, isRejected };\n}\n","'use client';\n\nimport { disconnect } from '@wagmi/core';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useConnection } from 'wagmi';\n\nimport { SiweAuthContextType, SiweNextAuthProviderProps, SIWESession } from '../types';\nimport { useInterval } from './useInterval';\nimport { useSiweSignature } from './useSiweSignature';\n\ntype SessionStatus = 'loading' | 'authenticated' | 'unauthenticated';\n\n/**\n * @function fetchSession\n * @description Fetches the current session status and data from the server.\n * @returns {Promise<{session: SIWESession | undefined, status: SessionStatus}>}\n */\nasync function fetchSession(): Promise<{ session: SIWESession | undefined; status: SessionStatus }> {\n try {\n const res = await fetch('/api/siwe/session');\n\n if (res.status === 401 || res.status === 404) {\n return { session: undefined, status: 'unauthenticated' };\n }\n\n if (!res.ok) {\n throw new Error('Failed to fetch session data.');\n }\n\n const data = await res.json();\n\n // NOTE: Data structure must match SiweSessionData {isLoggedIn, address, chainId}\n if (data.isLoggedIn && data.address && data.chainId) {\n return {\n session: { address: data.address, chainId: data.chainId },\n status: 'authenticated',\n };\n }\n return { session: undefined, status: 'unauthenticated' };\n } catch (e) {\n console.error('Error fetching session:', e);\n return { session: undefined, status: 'unauthenticated' };\n }\n}\n\n/**\n * @function useSiweAuthAdapter\n * Internal hook containing the core SIWE/Iron Session logic, acting as the authentication adapter.\n * @returns {SiweAuthContextType}\n */\nexport function useSiweAuthAdapter({\n wagmiConfig,\n enabled = true,\n nonceRefetchInterval = 5 * 60 * 1000, // 5 minutes (300,000 ms)\n onSignIn: providerOnSignIn,\n onSignOut: providerOnSignOut,\n getSiweMessageOptions,\n}: SiweNextAuthProviderProps): SiweAuthContextType {\n const [localSession, setLocalSession] = useState<SIWESession | undefined>(undefined);\n const [sessionStatus, setSessionStatus] = useState<SessionStatus>('loading');\n\n const { isReadyToSign, getSiweSignature, isRejected } = useSiweSignature({ wagmiConfig });\n\n const { address, chainId, isConnected } = useConnection({ config: wagmiConfig });\n\n const [isSigningInAfterContextChange, setIsSigningInAfterContextChange] = useState(false);\n\n const isAuthenticated = sessionStatus === 'authenticated';\n const isAuthenticating = sessionStatus === 'loading';\n const data: SIWESession | undefined = localSession;\n\n // --- SESSION REFETCH (equivalent to NextAuth's update) ---\n const updateSession = useCallback(async () => {\n setSessionStatus('loading');\n const { session, status } = await fetchSession();\n setLocalSession(session);\n setSessionStatus(status);\n return session;\n }, []);\n\n // --- NONCE REFETCH LOGIC (Managed by custom interval) ---\n useInterval(() => {\n if (isAuthenticated) {\n updateSession();\n }\n }, nonceRefetchInterval);\n\n /**\n * @async\n * @method signOutSiwe\n * Clears the session by calling the server API.\n */\n const signOutSiwe = useCallback(\n async (userOnSignOut?: () => void) => {\n await fetch('/api/siwe/logout', { method: 'POST' }); // Call your custom logout API\n setLocalSession(undefined);\n setSessionStatus('unauthenticated');\n\n providerOnSignOut?.(); // Execute provider callback\n userOnSignOut?.(); // Execute user callback\n },\n [providerOnSignOut],\n );\n\n /**\n * @async\n * @method signInWithSiwe\n * Executes the full SIWE authentication flow: signature -> verification -> session creation.\n */\n const signInWithSiwe = useCallback(\n async (userOnSignIn?: (session?: SIWESession) => void) => {\n if (!enabled) {\n throw new Error('SIWE is currently disabled via provider configuration.');\n }\n\n setSessionStatus('loading');\n\n try {\n // 1. Get Signature using the low-level hook\n const signatureData = await getSiweSignature(getSiweMessageOptions);\n\n if (!signatureData) {\n setSessionStatus('unauthenticated');\n return;\n }\n\n // 2. Send message and signature to your custom login API\n const response = await fetch('/api/siwe/login', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n message: signatureData.message,\n signature: signatureData.signature,\n }),\n });\n\n const responseBody = await response.json();\n\n if (!response.ok || responseBody.isLoggedIn !== true) {\n throw new Error(`Verification error: ${responseBody.message || 'Login failed.'}`);\n }\n\n console.log('SIWE Authentication successful.');\n\n // 3. Update session locally\n const finalSession: SIWESession = {\n address: responseBody.address,\n chainId: responseBody.chainId,\n };\n\n setLocalSession(finalSession);\n setSessionStatus('authenticated');\n\n // 4. Execute callbacks after successful sign-in\n providerOnSignIn?.(finalSession);\n userOnSignIn?.(finalSession);\n } catch (error) {\n await disconnect(wagmiConfig);\n setSessionStatus('unauthenticated');\n throw new Error(`SIWE Sign-In failed: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n },\n [enabled, getSiweSignature, getSiweMessageOptions, providerOnSignIn, wagmiConfig],\n );\n\n // --- OBLIGATORY SESSION RESET / AUTO-SIGN IN EFFECT ---\n\n useEffect(() => {\n if (isAuthenticated && enabled) {\n const sessionAddress = localSession?.address?.toLowerCase();\n const currentAddress = address?.toLowerCase();\n const sessionChainId = localSession?.chainId;\n const currentChainId = chainId;\n\n const addressChanged = sessionAddress && currentAddress && sessionAddress !== currentAddress;\n const chainChanged = sessionChainId && currentChainId && sessionChainId !== currentChainId;\n const walletDisconnected = !isConnected;\n\n if (addressChanged || chainChanged) {\n console.log('SIWE: Connector context changed (Address or Chain ID). Initiating re-authentication.');\n\n setIsSigningInAfterContextChange(true);\n\n // 1. OBLIGATORY SIGN OUT for the old session (security)\n signOutSiwe();\n } else if (walletDisconnected) {\n // Handle explicit connector disconnection: Always sign out.\n console.log('SIWE: Connector disconnected. Disconnecting session.');\n signOutSiwe();\n providerOnSignOut?.(); // Execute provider callback for disconnect\n }\n }\n }, [isAuthenticated, address, chainId, isConnected, localSession, signOutSiwe, enabled, providerOnSignOut]);\n\n // --- EFFECT TO EXECUTE AUTO SIGN-IN AFTER STATE RESET ---\n useEffect(() => {\n // Triggers when: 1. Flag is set AND 2. Status transitioned to 'unauthenticated'\n if (isSigningInAfterContextChange && sessionStatus === 'unauthenticated' && isReadyToSign && enabled) {\n console.log('SIWE: State reset detected. Attempting automatic sign-in to establish new session.');\n\n setIsSigningInAfterContextChange(false); // Reset flag\n\n // Auto sign-in execution\n signInWithSiwe().catch((e) => {\n throw new Error(\n `SIWE Auto Sign-In failed after context change: ${e instanceof Error ? e.message : 'Unknown error'}`,\n );\n });\n }\n }, [isSigningInAfterContextChange, sessionStatus, isReadyToSign, signInWithSiwe, enabled]);\n\n // --- FINAL EXPORT ---\n\n return useMemo(\n () => ({\n data,\n isReadyToSign,\n isRejected,\n isLoading: isAuthenticating,\n isSignedIn: isAuthenticated,\n signInWithSiwe,\n signOutSiwe,\n enabled,\n }),\n [data, isReadyToSign, isRejected, isAuthenticating, isAuthenticated, signInWithSiwe, signOutSiwe, enabled],\n );\n}\n","'use client';\n\nimport { useSiweAuthAdapter } from '../hooks/useSiweAuthAdapter';\nimport { SiweNextAuthProviderProps } from '../types';\nimport { SiweAuthContext } from './SiweAuthContext';\n\n/**\n * @component\n * @name SiweNextAuthProvider\n * @description Universal Provider for Sign-In with Ethereum (SIWE) using NextAuth.js.\n * This component handles the SIWE authentication logic.\n * It must be nested inside NextAuth's `<SessionProvider>` and your Wagmi Provider.\n * * **Note**: This provider requires the server-side NextAuth configuration to be set up.\n */\nexport function SiweNextAuthProvider(props: SiweNextAuthProviderProps) {\n const siweAuth = useSiweAuthAdapter(props);\n return <SiweAuthContext.Provider value={siweAuth}>{props.children}</SiweAuthContext.Provider>;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tuwaio/satellite-siwe-next-auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Oleksandr Tkach",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -51,25 +51,25 @@
|
|
|
51
51
|
}
|
|
52
52
|
],
|
|
53
53
|
"peerDependencies": {
|
|
54
|
-
"@wagmi/core": "
|
|
54
|
+
"@wagmi/core": "3.x.x",
|
|
55
55
|
"siwe": "3.x.x",
|
|
56
56
|
"next": "16.x.x",
|
|
57
57
|
"iron-session": "8.x.x",
|
|
58
58
|
"react": "19.x.x",
|
|
59
59
|
"viem": "2.x.x",
|
|
60
|
-
"wagmi": "
|
|
60
|
+
"wagmi": "3.x.x"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
-
"@wagmi/core": "^
|
|
64
|
-
"@types/react": "^19.2.
|
|
63
|
+
"@wagmi/core": "^3.0.0",
|
|
64
|
+
"@types/react": "^19.2.7",
|
|
65
65
|
"siwe": "^3.0.0",
|
|
66
|
-
"next": "16.0.
|
|
66
|
+
"next": "16.0.6",
|
|
67
67
|
"iron-session": "^8.0.4",
|
|
68
68
|
"react": "^19.2.0",
|
|
69
|
-
"tsup": "^8.5.
|
|
69
|
+
"tsup": "^8.5.1",
|
|
70
70
|
"typescript": "^5.9.3",
|
|
71
|
-
"viem": "^2.
|
|
72
|
-
"wagmi": "^
|
|
71
|
+
"viem": "^2.40.3",
|
|
72
|
+
"wagmi": "^3.0.2"
|
|
73
73
|
},
|
|
74
74
|
"scripts": {
|
|
75
75
|
"start": "tsup src/index.ts --watch",
|