<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.
Overview
Section titled “Overview”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.
Do you need this component?
Section titled “Do you need this component?”<seva-event-register> embeds its own sign-in form internally — if event registration is the only authenticated feature on your page, you do not need a standalone <seva-auth>. Users will be prompted to sign in directly within the registration flow.
Add a standalone <seva-auth> when you want to:
- Provide a visible sign-in/sign-out UI outside the registration flow
- Authenticate users before they interact with other components like
<seva-my-profile>,<seva-my-registrations>, or<seva-member-directory> - Give users a dedicated sign-out button on the page
Quick Example
Section titled “Quick Example”<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>Attributes
Section titled “Attributes”| Attribute | Type | Default | Description |
|---|---|---|---|
tenant-slug | string | '' | Required. Your organization’s tenant slug. |
api-url | string | 'https://api.seva.tools' | Base URL of the Seva API. |
view | AuthView | '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-up | boolean | false | When present, hides the “Sign up” link and sign-up form. Useful when the component is embedded inside <seva-event-register>. |
Events
Section titled “Events”| Event | Payload | When 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. |
AuthUser type
Section titled “AuthUser type”interface AuthUser { id: string; email: string; name: string;}AuthView type
Section titled “AuthView type”type AuthView = | "sign-in" | "sign-up" | "forgot-password" | "sms-otp" | "magic-link";Methods
Section titled “Methods”| Method | Signature | Description |
|---|---|---|
getToken() | () => string | null | Returns the current session token, or null if not authenticated. |
getUser() | () => AuthUser | null | Returns the current user object, or null if not authenticated. |
signOut() | () => void | Clears auth state and fires seva:signed-out. |
setView(view) | (view: AuthView) => void | Programmatically switch to a different auth view. |
Auth flows
Section titled “Auth flows”Email / Password
Section titled “Email / Password”The default view. The user enters email and password. On success, seva:authenticated fires.
Sign Up
Section titled “Sign Up”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.
Forgot Password
Section titled “Forgot Password”Sends a password-reset email. Always shows a success message regardless of whether the email exists (to prevent email enumeration).
Magic Link
Section titled “Magic Link”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.
SMS OTP
Section titled “SMS OTP”Two-step flow: (1) user enters phone number and receives a code, (2) user enters the code. On successful verification, seva:authenticated fires.
Google OAuth
Section titled “Google OAuth”Opens a popup window for Google sign-in. The popup communicates back via postMessage. If popups are blocked, an error is shown.
Session lifecycle
Section titled “Session lifecycle”Auth state is stored in localStorage under the key seva-auth-{tenant-slug}. Sessions work like this:
- A login session lasts 30 days.
- As long as the user visits the site at least once a day, their session is automatically extended in the background — they won’t be interrupted or asked to sign in again.
- If a user is inactive for more than 30 days, they will need to sign in again the next time they visit.
When sessions end
Section titled “When sessions end”A session ends when:
- 30 days pass with no activity on the site
- The user clicks Sign Out (clears localStorage and fires
seva:signed-out) - The user clears browser localStorage for the host domain
Full Example
Section titled “Full Example”<!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>