Stormkit Auth adds end-user authentication to the application you host on Stormkit. Your visitors can register and sign in with email and password, a magic link, or an OAuth provider (Google, X / Twitter), and your app receives a signed session token it can use to identify the user on every request.
This is different from the Auth Wall, which gates access to a deployment for your team. Stormkit Auth is for your application's own users.
You configure it under Environment > Authentication.
Requirements
- Stormkit Auth is available on self-hosted installations only.
- The environment must have a database attached — users and sessions are stored there. If no database is attached, the Authentication tab will prompt you to configure one first.
- The Magic Link and email / password providers send email (sign-in links and verification messages), so the environment's Mailer must be configured for them to actually deliver. The OAuth providers (Google, X) don't need the Mailer.
All authentication endpoints are served from your app's own hosting domain
under the /_stormkit/auth path. There is nothing to install in your
application: Stormkit intercepts these paths before your deployment is served.
The high-level flow is:
skauth key in localStorage.?verified=true;
the OAuth and cross-origin flows redirect to the plain Success URL.skauth token and sends it as a
Authorization: Bearer <token> header on subsequent requests.X-User-Id and X-User-Email headers to your backend / API. These headers
are always stripped from incoming requests first, so they cannot be spoofed.The Authentication tab has two parts: a set of global settings and the list of providers.
| Setting | Description |
|---|---|
| Success callback URL | A relative URL (e.g. /auth/success) the browser is redirected to after a successful sign-in. At this URL your browser code can read the skauth item from localStorage. |
| Session TTL | How long a session token stays valid. Accepts durations like 30min, 12h, 7d, 1w, 1mo, 1y. |
| Allowed origins | Optional. One origin per line (scheme + host, no path). Required only when your frontend runs on a different domain than the auth host (a decoupled frontend or a native app). Leave it empty for single-host setups. |
Remember to click Save after changing these settings.
Open a provider from the list to configure and enable it. Disabling a provider does not delete its existing users.
No credentials to configure — just enable it. Users register and sign in programmatically:
POST /_stormkit/auth/register with a JSON body { "email": "...", "password": "..." }. Returns a session JWT on success.POST /_stormkit/auth/login with the same body to sign an existing user in.GET /_stormkit/auth/verify is used to confirm email addresses. The
verification email needs the Mailer configured; as
with Magic Link, unsent emails are still viewable under Mailer > Sent
Emails.Passwordless sign-in via a one-time link sent by email.
From header for magic-link emails
(e.g. Acme <noreply@acme.com>).GET /_stormkit/auth/magic?email=user@example.com. The
endpoint returns 201 with no content and emails the user a link./_stormkit/auth/magic?token=<token>, which
exchanges the token for a session JWT stored in localStorage and redirects
to your Success callback URL.Magic Link requires the Mailer to be configured to deliver links. If the Mailer is not configured, the email is still recorded and visible under Environment > Mailer > Sent Emails — but it is not actually delivered, so this is only useful for local testing.
OAuth 2.0 providers require a Client ID and Client Secret from the provider's developer console.
When you open an OAuth provider, the drawer shows the exact Callback URL to
register with the provider. Because an app can be served from several domains,
pick the domain from the dropdown and register the matching callback URL —
https://<your-domain>/_stormkit/auth/callback — for every domain you sign
in from.
Start the OAuth flow by redirecting the user to the Authorization URL on your
own domain, e.g. https://app.example.com/_stormkit/auth/google. Optionally
append ?redirect=<origin> to control where the user returns afterwards;
otherwise the request's Origin / Referer is used.
After a successful sign-in, read the token and attach it to your API calls:
// After the redirect to your Success callback URL
const token = JSON.parse(localStorage.getItem("skauth"));
const res = await fetch("/api/me", {
headers: { Authorization: `Bearer ${token}` },
});
On the server side, your deployment receives the validated identity as request headers:
X-User-Id — the user's external identifier.X-User-Email — the user's email address.To keep an active user signed in without forcing a new sign-in, exchange a still valid token for a fresh one:
POST /_stormkit/auth/refresh with the current Authorization: Bearer <token>
header. Returns a new token with the same identity.Call this proactively (for example on app open and on a periodic timer) so the token never reaches its TTL while the user is active. Expired tokens are rejected — the user must sign in again.
When your frontend is served from a different origin than the auth host (a
separately deployed SPA, or a native/mobile app), add that frontend's origin to
Allowed origins. Stormkit then completes sign-in by bouncing the browser
through a short-lived one-time code, landing the user back on your frontend with
the token injected into localStorage there — even though that frontend has no
auth configuration of its own.
If a provider is enabled but no allowed origins are set and your frontend runs on a separate domain, sign-in will return users to the auth host instead of your app. The Authentication tab warns you about this.
When a sign-in fails (an invalid, expired, or already-used token, for example),
the user is redirected back to your Success callback URL with a
login_error query parameter holding a human-readable message, instead of a
Stormkit error page. Read it on your callback page to show a friendly message:
const params = new URLSearchParams(window.location.search);
const error = params.get("login_error");
Sign-ins from different providers that share the same email address are linked to a single user, so a person who first signed in with Google and later via a magic link remains one account.
You can review your application's users under Environment > Auth Users, or list them programmatically with the public API:
GET /v1/auth/users?envId=<id>&from=<offset> — requires a user-scoped API
key. Returns a page of users and a hasNextPage flag.https://<your-domain>/_stormkit/auth/callback
for the domain the user signs in on. Register it for every domain you use.POST /_stormkit/auth/refresh periodically so active sessions are renewed
before they expire.