Security News
New Proposed CISA Mandate Would Require Critical Infrastructure to Report Ransom Payments Within 24 Hours
CISA has proposed a set of new rules that would require critical infrastructure to report cyber incidents and ransom payments.
@randombits/use-siwe
Advanced tools
React hook and API endpoints that provide Sign In With Ethereum support
Weekly downloads
Readme
Use-siwe is a library that provides react hooks and API endpoints that make it dead simple to add Sign-In with Ethereum functionality to your react application.
The easiest way to use this library is with RainbowKit! Check out the RainbowKit authentication adapter for use-siwe here: https://github.com/random-bits-studio/rainbowkit-use-siwe-auth
To install use-siwe
and it's dependencies run the following command:
npm install @randombits/use-siwe wagmi ethers iron-session
iron-session
Copy and paste the following code into a new file in your project:
// lib/ironOptions.ts
import { IronSessionOptions } from 'iron-session';
if (!process.env.IRON_SESSION_PASSWORD)
throw new Error('IRON_SESSION_PASSWORD must be set');
const ironOptions: IronSessionOptions = {
password: process.env.IRON_SESSION_PASSWORD,
cookieName: 'session',
cookieOptions: {
secure: process.env.NODE_ENV === "production",
},
};
declare module "iron-session" {
interface IronSessionData {
address?: string | undefined;
nonce?: string | undefined;
}
}
export default ironOptions;
Remember to set IRON_SESSION_PASSWORD in your .env.local
file for
development, and in your production environment through your hosting
provider settings. The password must be at least 32 characters long. You can
use https://1password.com/password-generator/ to generate strong passwords.
For full reference of possible options see: https://github.com/vvo/iron-session#ironoptions
Typing session data
The type definition of IronSessionData
in the example above provides a type
definition to the data passed to api functions in req.session
. address
and
nonce
are used and set by use-siwe; if you plan on storing other data in the
session, feel free to add additional types here.
For more information see: https://github.com/vvo/iron-session#typing-session-data-with-typescript
Copy and past the following code into pages/api/auth/[[...route]].ts
:
import { withIronSessionApiRoute } from "iron-session/next";
import ironOptions from "lib/ironOptions";
import { siweApi } from "@randombits/use-siwe/next"
export default withIronSessionApiRoute(siweApi(), ironOptions);
To add auth routes to your existing express API, add the following:
import express from "express";
import { ironSession } from "iron-session/express";
import ironOptions from "./ironOptions.js";
import { authRouter } from "@randombits/use-siwe/express";
const app = express();
// Add iron session middleware before all routes that will use session data
app.use(ironSession(ironOptions));
// Your existing api routes here...
// Add use-siwe auth routes
app.use('/auth', authRouter());
app.listen(3001);
SiweProvider
Any component that uses the any of the use-siwe hooks must be wrapped with the
SiweProvider
component. For a Next.js application we recommend doing so in
pages/_app.tsx
like in the example below:
// pages/_app.tsx
import type { AppProps } from 'next/app';
import { configureChains, mainnet } from 'wagmi';
import { publicProvider } from 'wagmi/providers/public';
import { SiweProvider } from '@randombits/use-siwe';
const { chains, provider, webSocketProvider } = configureChains(
[mainnet],
[publicProvider()],
);
const client = createClient({
autoConnect: true,
provider,
webSocketProvider,
});
export default function MyApp({ Component, pageProps }: AppProps) {
return (
<WagmiConfig client={client}>
<SiweProvider>
<Component {...pageProps} />
</SiweProvider>
</WagmiConfig>
);
}
Important: The SiweProvider
must be inside a WagmiConfig
component.
Check to see is a user is authenticated with the useSession
hook like in the
example below:
import { useSession } from "@randombits/use-siwe";
export const AuthCheck = () => {
const { isLoading, authenticated, address } = useSession();
if (isLoading) return <p>Loading...</p>;
if (!authenticated) return <p>Not authenticated</p>;
return <p>{address} is Authenticated</p>;
};
For API routes, wrap your API handler with withIronSessionApiRoute
and check
to see if req.session.address
is set. If a user is authenticated,
req.session.address
will be set to their address, otherwise it will be
undefined
.
import ironOptions from '@/lib/ironOptions'
import { withIronSessionApiRoute } from 'iron-session/next/dist'
import type { NextApiHandler } from 'next'
const handler: NextApiHandler = (req, res) => {
if (!req.session.address) return res.status(401).send("Unauthorized");
res.status(200).send(`Hello, ${req.session.address}!`);
}
export default withIronSessionApiRoute(handler, ironOptions);
Login the user by calling the signIn
function returned by the useSignIn
hook:
import { useSignIn } from "@randombits/use-siwe";
const SignInButton = () => {
const { signIn, isLoading } = useSignIn();
return <button onClick={() => signIn()} disabled={isLoading}>Sign In with Ethereum</button>;
};
Logout the user by calling the signOut
function returned by the useSignOut
hook:
import { useSignOut } from "@randombits/use-siwe";
const SignOutButton = () => {
const { signOut, isLoading } = useSignOut();
return <button onClick={() => signOut()} disabled={isLoading}>Sign Out</button>;
};
Use-siwe accepts an object of options. Currently this consists of one optional setting:
const options: UseSiweOptions = {
baseUrl: "/v2/api/auth",
};
baseUrl
, optional: The base url for the auth API endpoints that is
prepended to all requests. Defaults to: /api/auth
Context provider component that must wrap all components that use useSession
,
useSignIn
, useSignOut
, or useOptions
hooks.
import type { AppProps } from 'next/app';
import { SiweProvider } from '@randombits/use-siwe';
export default function MyApp({ Component, pageProps }: AppProps) {
return <SiweProvider>
<Component {...pageProps} />
</SiweProvider>;
}
options
, Optional: A UseSiweOptions
object.A hook that returns the the current state of the users session.
import { useSession } from "@randombits/use-siwe";
export const Component = () => {
const { isLoading, authenticated, address } = useSession();
if (isLoading) return <div>Loading...</div>;
if (!authenticated) return <div>Not Signed In</div>;
return <div>Hello, {address}!</div>;
};
Returns a UseQueryResult
(ref)
augmented with the following:
{
authenticated: boolean;
address?: string;
nonce?: string;
} & UseQueryResult
A hook that returns a signIn
function that will initiate a SIWE flow, as well
as the status of that signIn process.
import { useSignIn } from "@randombits/use-siwe";
const SignInButton = () => {
const { signIn, isLoading } = useSignIn();
return <button onClick={() => signIn()} disabled={isLoading}>Sign In with Ethereum</button>;
};
{
onSuccess: () => void,
onError: () => void,
}
Returns a UseMutationResult
(ref)
augmented with the following:
{
signIn: () => void,
SignInAsync: () => Promise<void>,
} & UseMutationResult
A hook that returns a signOut
function that when called will sign out the
current user and disconnect their wallet.
import { useSignOut } from "@randombits/use-siwe";
const SignOutButton = () => {
const { signOut, isLoading } = useSignOut();
return <button onClick={() => signOut()} disabled={isLoading}>Sign Out</button>;
};
{
onSuccess: () => void,
onError: () => void,
}
Returns a UseMutationResult
(ref)
augmented with the following:
{
signOut: () => void,
SignOutAsync: () => Promise<void>,
} & UseMutationResult
A hook that simply returns the options that have been set by in the
SiweProvider
component.
import { useOptions, verify } from "@randombits/use-siwe";
const verifyButton = (props) => {
const options = useOptions();
const handleClick = () => verify({
message: props.message,
signature: props.signature,
}, options);
return <button onClick={() => handleClick()}>Verify Signature</button>;
};
useSiweOptions
A function that returns a NextApiHandler
that will handle all auth API
routes.
import { withIronSessionApiRoute } from "iron-session/next";
import ironOptions from "lib/ironOptions";
import { siweApi } from "@randombits/use-siwe/next"
export default withIronSessionApiRoute(siweApi(), ironOptions);
NextApiHandler
A function that returns an express Router
that will handle all auth API
routes.
import express from "express";
import { ironSession } from "iron-session/express";
import ironOptions from "./ironOptions.js";
import { authRouter } from "@randombits/use-siwe/express";
const app = express();
app.use(ironSession(ironOptions));
app.use('/auth', authRouter());
app.listen(3001);
Router
A function to retrieve the session data where using a hook doesn't make sense.
import { getSession } from "@randombits/use-siwe";
const addressOrNull = async () => {
const { address } = await getSession();
if (!address) return null;
return address;
};
options?: UseSiweOptions
{
authenticated: boolean;
address?: string;
nonce?: string;
}
Returns a SiweMessage
for the given address, chainId, and nonce.
import { createMessage, getMessageBody } from "@randombits/use-siwe";
const debugMessage = (address, chainId, nonce) => {
const message = createMessage({ address, chainId, nonce });
const messageBody = getMessageBody({ message });
console.log({ message, messageBody });
};
args: MessageArgs
type MessageArgs = {
address: string,
chainId: number,
nonce: string,
};
SiweMessage
Returns a message ready to be signed according with the type defined in the SiweMessage object.
import { createMessage, getMessageBody } from "@randombits/use-siwe";
const debugMessage = (address, chainId, nonce) => {
const message = createMessage({ address, chainId, nonce });
const messageBody = getMessageBody({ message });
console.log({ message, messageBody });
};
args: { message: SiweMessage }
string
Takes a message and a signature as arguments and attempts to verify them using the auth API. A successful verification will create a session for the user.
import { verify } from "@randombits/use-siwe";
const verifyButton = (props) => {
const handleClick = () => {
const success = verify({
message: props.message,
signature: props.signature,
});
if (!success) return console.error("VERIFICATION FAILED");
console.log("SIGNATURE VERIFIED");
};
return <button onClick={() => handleClick()}>Verify Signature</button>;
};
args: VerifyArgs
options?: UseSiweOptions
type VerifyArgs = {
message: SiweMessage,
signature: string,
};
boolean
A function to sign out the user where using a hook doesn't make sense.
import { signOut } from "@randombits/use-siwe";
// Logout a user after 1 hour
setTimeout(async () => {
await signOut();
window.location.href = "/session-expired";
}, 60 * 60 * 1000);
options?: UseSiweOptions
Promise<void>
FAQs
React hook and API endpoints that provide Sign In With Ethereum support
The npm package @randombits/use-siwe receives a total of 3 weekly downloads. As such, @randombits/use-siwe popularity was classified as not popular.
We found that @randombits/use-siwe demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
CISA has proposed a set of new rules that would require critical infrastructure to report cyber incidents and ransom payments.
Security News
Redis is no longer OSS, breaking its explicit commitment to remain under the BSD 3-Clause License forever. This has angered contributors who are now working to fork the software.
Product
Socket AI now enables 'AI detected potential malware' alerts by default, ensuring users benefit from AI-powered state-of-the-art malware detection without needing to opt-in.