Sign in with 1auth
Add passkey authentication to your app with a single method call. Users authenticate with Face ID or Touch ID - no passwords, no seed phrases.
Authentication
import { OneAuthClient } from '@rhinestone/1auth';
const client = new OneAuthClient({
providerUrl: 'https://passkey.1auth.box',
});
// Open the authentication modal
const result = await client.authWithModal();
if (result.success) {
console.log('Connected as:', result.user?.username);
console.log('Address:', result.user?.address); // typed `0x${string}`
}How It Works
- User clicks sign in - Your app calls
authWithModal() - 1auth modal opens - User enters their username or creates a new account
- Passkey prompt - Device prompts for Face ID / Touch ID
- Success - You receive user details and wallet address
The entire flow happens in a secure iframe. Your app never sees the passkey credentials.
Message Signing
Request the user to sign a message for verification:
const result = await client.signMessage({
username: 'alice',
message: `Sign in to MyApp\nTimestamp: ${Date.now()}`,
description: 'Verify your identity',
});
if (result.success) {
console.log('Signature:', result.signature);
// Verify signature on your backend
}SignMessageOptions
| Property | Type | Required | Description |
|---|---|---|---|
username | string | Yes | Username of the signer |
message | string | Yes | Human-readable message to sign |
description | string | No | Description shown in the signing dialog |
metadata | Record<string, unknown> | No | Additional data to display |
AuthResult
authWithModal() returns an AuthResult:
import type { AuthResult } from '@rhinestone/1auth';
interface AuthResult {
success: boolean;
/** Authenticated user (present when success is true) */
user?: {
id: string;
username?: string;
address: `0x${string}`;
};
/** Error details when success is false */
error?: {
code: string; // e.g. "USER_CANCELLED"
message: string;
};
}Challenge-Based Authentication
Use authenticate() for server-verified login. It returns an AuthenticateResult — the same shape as AuthResult plus a challenge object with the cryptographic signature.
const result = await client.authenticate({
challenge: `Login to MyApp\nTimestamp: ${Date.now()}\nNonce: ${crypto.randomUUID()}`
});
if (result.success && result.challenge) {
// Send signature + signedHash to your backend for verification
await fetch('/api/verify', {
method: 'POST',
body: JSON.stringify({
username: result.user?.username,
address: result.user?.address,
signature: result.challenge.signature,
signedHash: result.challenge.signedHash,
}),
});
}AuthenticateResult
authenticate() returns an AuthenticateResult, which extends AuthResult with a challenge field:
import type { AuthenticateResult } from '@rhinestone/1auth';
interface AuthenticateResult extends AuthResult {
/** Present when a challenge was provided in the options */
challenge?: {
signature: WebAuthnSignature;
signedHash: `0x${string}`;
};
}Example: Protected Route
import { useState, useEffect } from 'react';
import { OneAuthClient } from '@rhinestone/1auth';
const client = new OneAuthClient({
providerUrl: 'https://passkey.1auth.box',
});
function App() {
const [user, setUser] = useState(null);
const handleSignIn = async () => {
const result = await client.authWithModal();
if (result.success && result.user) {
setUser({ username: result.user.username, address: result.user.address });
}
};
if (!user) {
return (
<button onClick={handleSignIn}>
Sign in with 1auth
</button>
);
}
return (
<div>
<p>Welcome, {user.username}!</p>
<p>Address: {user.address}</p>
</div>
);
}