Skip to main content

Introduction to Keyban Auth

Keyban Auth is a flexible authentication layer that lets you manage access to non-custodial wallets - with or without your own identity system.

Keyban Auth overview

Keyban Auth is a secure and modular authentication layer designed to simplify the way users access non-custodial wallets.
It enables integrators to offer custom login experiences while benefiting from high-security key management and seamless wallet orchestration.

Whether you need a branded login interface, integration with an existing SSO, or support for modern authentication flows (social login, OTP, passkeys), Keyban Auth adapts to your needs with minimal integration effort.

You can fully customize the login interface using secure components like KeybanInput, which ensures sensitive data is isolated in secure iframes, and useKeybanAuth hook for authentication logic, adapting them to your design system and branding while maintaining the highest security standards.


Developer Entry Points

To implement authentication in your React app, use:

  • useKeybanAuth – to manage authentication state, session lifecycle, and access to the wallet.
  • KeybanInput – secure iframe-based input component for handling sensitive authentication data.

Both are available via the Keyban SDK for React and compatible with React Native.

The KeybanInput component ensures that sensitive user data (passwords, OTP codes, phone numbers) is handled securely through iframe isolation, while useKeybanAuth provides the authentication logic and state management.

Example: Secure Phone-based Login with OTP using KeybanInput

import { KeybanInput, useKeybanAuth } from "@keyban/sdk-react";
import { useState } from "react";

export default function Login() {
const [step, setStep] = useState<"phone" | "otp">("phone");
const { passwordlessStart, passwordlessLogin, isAuthenticated } = useKeybanAuth();

const handlePhoneSubmit = async () => {
await passwordlessStart({
connection: "sms",
phoneCallingCode: "33", // France country code
phoneInputName: "phone",
});
setStep("otp");
};

const handleOtpSubmit = async () => {
await passwordlessLogin({
connection: "sms",
phoneCallingCode: "33",
phoneInputName: "phone",
otpInputName: "otp",
});
};

if (isAuthenticated) return <div>You're in!</div>;

return step === "phone" ? (
<div>
<KeybanInput
name="phone"
type="tel"
onFocus={() => console.log("Phone input focused")}
/>
<button onClick={handlePhoneSubmit}>Send Code</button>
</div>
) : (
<div>
<KeybanInput
name="otp"
inputMode="numeric"
inputStyles={{ textAlign: "center" }}
/>
<button onClick={handleOtpSubmit}>Verify</button>
</div>
);
}

This minimal integration uses useKeybanAuth() to perform a secure OTP-based login flow with KeybanInput components. The inputs are rendered in secure iframes, ensuring sensitive data like phone numbers and OTP codes are isolated from the main application context.


KeybanInput Component

The KeybanInput component is a secure, iframe-based input designed specifically for handling sensitive authentication data. It provides a seamless way to collect user credentials while maintaining the highest security standards.

Key Security Features

  • Iframe Isolation: All inputs are rendered in sandboxed iframes to prevent data leakage
  • Cross-Origin Protection: Secure communication between iframe and parent application
  • No Direct Access: Input values are never accessible from the parent application context

Common Authentication Patterns

Email/Password Login

import { KeybanInput, useKeybanAuth } from "@keyban/sdk-react";

export default function EmailLogin() {
const { passwordLogin } = useKeybanAuth();

const handleLogin = async () => {
await passwordLogin({
usernameInputName: "email",
passwordInputName: "password",
});
};

return (
<form>
<div>
<label>Email:</label>
<KeybanInput name="email" type="email" />
</div>
<div>
<label>Password:</label>
<KeybanInput name="password" type="password" />
</div>
<button type="button" onClick={handleLogin}>
Login
</button>
</form>
);
}

Email OTP Authentication

import { KeybanInput, useKeybanAuth } from "@keyban/sdk-react";
import { useState } from "react";

export default function EmailOTPLogin() {
const [showOtp, setShowOtp] = useState(false);
const { passwordlessStart, passwordlessLogin } = useKeybanAuth();

const handleSendCode = async () => {
await passwordlessStart({
connection: "email",
emailInputName: "email",
});
setShowOtp(true);
};

const handleVerifyCode = async () => {
await passwordlessLogin({
connection: "email",
emailInputName: "email",
otpInputName: "otp",
});
};

return (
<div>
<KeybanInput name="email" type="email" />

{showOtp && (
<KeybanInput
name="otp"
inputMode="numeric"
inputStyles={{ textAlign: "center" }}
/>
)}

<button onClick={showOtp ? handleVerifyCode : handleSendCode}>
{showOtp ? "Verify Code" : "Send Code"}
</button>
</div>
);
}

Material-UI Integration

import { KeybanInput, useKeybanAuth } from "@keyban/sdk-react";
import { TextField, Button, Box } from "@mui/material";

export default function MaterialUILogin() {
const { passwordlessStart, passwordlessLogin } = useKeybanAuth();
const [showOtp, setShowOtp] = useState(false);

return (
<Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
<TextField
label="Email"
variant="outlined"
fullWidth
slots={{
htmlInput: () => (
<Box
component={KeybanInput}
name="email"
type="email"
sx={{ flexGrow: 1 }}
/>
),
}}
/>

{showOtp && (
<TextField
label="Verification Code"
variant="outlined"
fullWidth
slots={{
htmlInput: () => (
<Box
component={KeybanInput}
name="otp"
inputMode="numeric"
inputStyles={{ textAlign: "center" }}
sx={{ flexGrow: 1 }}
/>
),
}}
/>
)}

<Button
variant="contained"
onClick={showOtp ? handleVerifyCode : handleSendCode}
>
{showOtp ? "Verify Code" : "Continue with Email"}
</Button>
</Box>
);
}

International Phone Number Input

import { KeybanInput, useKeybanAuth } from "@keyban/sdk-react";
import { MuiTelInput } from "mui-tel-input";
import { useState } from "react";

const PhoneInput = () => (
<Box
component={KeybanInput}
type="tel"
name="phone"
sx={{ flexGrow: 1, p: 2, pl: 0 }}
/>
);

export default function PhoneLogin() {
const [phoneCallingCode, setPhoneCallingCode] = useState("33");
const [showOtp, setShowOtp] = useState(false);
const { passwordlessStart, passwordlessLogin } = useKeybanAuth();

const handleSendCode = async () => {
await passwordlessStart({
connection: "sms",
phoneCallingCode,
phoneInputName: "phone",
});
setShowOtp(true);
};

const handleVerifyCode = async () => {
await passwordlessLogin({
connection: "sms",
phoneCallingCode,
phoneInputName: "phone",
otpInputName: "otp",
});
};

return (
<div>
<MuiTelInput
name="phone"
defaultCountry="FR"
value={`+${phoneCallingCode}`}
forceCallingCode
onChange={(_, infos) =>
setPhoneCallingCode(infos.countryCallingCode ?? "")
}
fullWidth
slots={{ htmlInput: PhoneInput }}
/>

{showOtp && (
<KeybanInput
name="otp"
inputMode="numeric"
inputStyles={{ textAlign: "center" }}
/>
)}

<button onClick={showOtp ? handleVerifyCode : handleSendCode}>
{showOtp ? "Verify" : "Continue"}
</button>
</div>
);
}

Advanced Features

Focus Management

import { KeybanInput, KeybanInputRef } from "@keyban/sdk-react";
import { useRef } from "react";

export default function FocusExample() {
const emailRef = useRef<KeybanInputRef>(null);
const passwordRef = useRef<KeybanInputRef>(null);

const focusEmail = () => emailRef.current?.focus();
const focusPassword = () => passwordRef.current?.focus();

return (
<div>
<KeybanInput ref={emailRef} name="email" type="email" />
<KeybanInput ref={passwordRef} name="password" type="password" />

<button onClick={focusEmail}>Focus Email</button>
<button onClick={focusPassword}>Focus Password</button>
</div>
);
}

Custom Styling

import { KeybanInput } from "@keyban/sdk-react";

export default function StyledInputs() {
return (
<div>
{/* OTP input with centered text */}
<KeybanInput
name="otp"
inputMode="numeric"
inputStyles={{
textAlign: "center",
fontSize: "24px",
backgroundColor: "#f5f5f5",
color: "#333"
}}
style={{
border: "2px solid #007bff",
borderRadius: "8px",
padding: "12px"
}}
/>

{/* Email input with custom appearance */}
<KeybanInput
name="email"
type="email"
inputStyles={{
fontSize: "16px",
color: "#2c3e50"
}}
className="custom-input-class"
/>
</div>
);
}

Best Practices

  1. Always use KeybanInput for sensitive data: Never use regular HTML inputs for passwords, OTP codes, or other sensitive information
  2. Proper naming: Use descriptive names that match your authentication flow (e.g., "email", "phone", "otp")
  3. Input types: Always specify appropriate input types (email, tel, password) for better UX
  4. Error handling: Implement proper error handling for authentication failures
  5. Loading states: Show loading indicators during authentication processes
  6. Accessibility: Ensure proper labeling and keyboard navigation