Skip to content

<seva-auth>

The <seva-auth> component renders a complete authentication UI. It supports email/password sign-in, account creation, forgot password, magic link, SMS OTP, and Google OAuth — all in a single element.

When the user is not authenticated, the component displays a sign-in form with links to alternate auth methods. After successful authentication, it shows the user’s name, email, and a sign-out button. Auth state is persisted in localStorage and restored on page load.

<script type="module" src="YOUR_COMPONENTS_URL/seva-auth.js"></script>
<seva-auth
tenant-slug="my-club"
api-url="https://api.seva.tools">
</seva-auth>
<script>
const auth = document.querySelector('seva-auth');
auth.addEventListener('seva:authenticated', (e) => {
console.log('User:', e.detail.user);
console.log('Token:', e.detail.token);
});
</script>
AttributeTypeDefaultDescription
tenant-slugstring''Required. Your organization’s tenant slug.
api-urlstring'https://api.seva.tools'Base URL of the Seva API.
viewAuthView'sign-in'Initial view. One of: 'sign-in', 'sign-up', 'forgot-password', 'sms-otp', 'magic-link'.
theme'light' | 'dark''light'Color theme. Set via JavaScript property.
hide-sign-upbooleanfalseWhen present, hides the “Sign up” link and sign-up form. Useful when the component is embedded inside <seva-event-register>.
EventPayloadWhen it fires
seva:authenticated{ user: AuthUser, token: string }User successfully signs in or signs up.
seva:signed-out{}User signs out (via UI or signOut() method).
seva:error{ message: string }An auth error occurs (bad credentials, network failure, etc.).
seva:view-changed{ view: AuthView }The component switches between views (sign-in, sign-up, etc.).
seva:pending{ message: string }Sign-up succeeded but the account requires admin approval.
interface AuthUser {
id: string;
email: string;
name: string;
}
type AuthView = 'sign-in' | 'sign-up' | 'forgot-password' | 'sms-otp' | 'magic-link';
MethodSignatureDescription
getToken()() => string | nullReturns the current session token, or null if not authenticated.
getUser()() => AuthUser | nullReturns the current user object, or null if not authenticated.
signOut()() => voidClears auth state and fires seva:signed-out.
setView(view)(view: AuthView) => voidProgrammatically switch to a different auth view.

The default view. The user enters email and password. On success, seva:authenticated fires.

Available unless hide-sign-up is set. Collects first name, last name, email, and password. If the tenant requires approval, the component shows a pending message and fires seva:pending instead.

Sends a password-reset email. Always shows a success message regardless of whether the email exists (to prevent email enumeration).

Sends a sign-in link to the user’s email. When the user clicks the link, they are redirected back with a seva-token query parameter. The component detects this automatically, validates the token, and fires seva:authenticated.

Two-step flow: (1) user enters phone number and receives a code, (2) user enters the code. On successful verification, seva:authenticated fires.

Opens a popup window for Google sign-in. The popup communicates back via postMessage. If popups are blocked, an error is shown.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sign In</title>
<script type="module" src="YOUR_COMPONENTS_URL/seva-auth.js"></script>
<style>
body { font-family: system-ui, sans-serif; max-width: 400px; margin: 2rem auto; }
#status { margin-top: 1rem; padding: 0.75rem; border-radius: 0.5rem; font-size: 0.875rem; }
.signed-in { background: #dcfce7; color: #166534; }
.signed-out { background: #fef3c7; color: #92400e; }
</style>
</head>
<body>
<seva-auth id="auth"
tenant-slug="my-club"
api-url="https://api.seva.tools">
</seva-auth>
<div id="status" class="signed-out">Not signed in</div>
<script>
const auth = document.getElementById('auth');
const status = document.getElementById('status');
auth.addEventListener('seva:authenticated', (e) => {
status.textContent = 'Signed in as ' + e.detail.user.name;
status.className = 'signed-in';
});
auth.addEventListener('seva:signed-out', () => {
status.textContent = 'Not signed in';
status.className = 'signed-out';
});
auth.addEventListener('seva:error', (e) => {
console.error('Auth error:', e.detail.message);
});
</script>
</body>
</html>