Login with EAuth
Ten minutes, ending with a signed-in user and their email address in your application.
1. Register your application
Go to panel.elchi.dev and create an application.
Choose the type carefully, because it cannot be changed afterwards:
| Type | Use when | Authenticated by |
|---|---|---|
| Public | Browser app, mobile app, anything whose code the user can read | PKCE alone |
| Confidential | Server-rendered app, backend service | PKCE and a client secret |
A single-page application is public. Choosing confidential would put a secret into a JavaScript bundle, where it is not a secret.
Add your redirect URI exactly as your application will send it. A trailing slash makes it a different URI, and wildcards are refused.
2. Point your library at the discovery URL
https://auth.elchi.dev/.well-known/openid-configuration
Every conforming OpenID Connect library takes that one address and configures each endpoint itself. You should not need to hardcode any other URL.
3. Send the user to sign in
Generate a PKCE pair, keep the verifier, send the challenge:
const verifier = base64url(crypto.getRandomValues(new Uint8Array(48)));
const challenge = base64url(
await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier))
);
sessionStorage.setItem("pkce_verifier", verifier);
const url = new URL("https://auth.elchi.dev/authorize");
url.searchParams.set("response_type", "code");
url.searchParams.set("client_id", CLIENT_ID);
url.searchParams.set("redirect_uri", REDIRECT_URI);
url.searchParams.set("scope", "openid profile email");
url.searchParams.set("state", crypto.randomUUID());
url.searchParams.set("code_challenge", challenge);
url.searchParams.set("code_challenge_method", "S256");
location.assign(url);
Store the state value. You will compare it in the next step.
4. Handle the redirect back
The user returns to your redirect URI with three parameters:
?code=...&state=...&iss=https://auth.elchi.dev
Check all three before doing anything else:
statemust equal what you stored. If it does not, the request did not start in this browser session, and you should abandon it.issmust be exactlyhttps://auth.elchi.dev. This is RFC 9207, and checking it is what stops a mix-up attack when your application talks to more than one provider.codeis single use and expires in sixty seconds.
5. Exchange the code for tokens
From your server, never from the browser:
curl -X POST https://auth.elchi.dev/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d grant_type=authorization_code \
-d code="$CODE" \
-d redirect_uri="$REDIRECT_URI" \
-d code_verifier="$VERIFIER"
A public client omits -u and sends client_id in the body instead.
You get back an access token, an ID token, and a refresh token if you asked for
offline_access.
6. Read who signed in
The ID token is a signed JWT. Verify it against our JWKS, then read the claims:
{
"iss": "https://auth.elchi.dev",
"aud": "eauth_cnf_...",
"sub": "01a06188-ea2a-7c15-8ac2-d33d2eacd4db",
"name": "Anna Muster",
"email": "anna@example.com",
"email_verified": false
}
Use sub as the user's identity in your database. It never changes. Do not key
on email: people change addresses, and two different people can hold the same
address years apart.
What to do next
The playground builds a real authorization request from your own client id so you can watch the flow happen before writing any code.