Add sign-in to your site¶
The common case. Your site redirects to the provider, the person signs in there, and they come back with a token that says who they are.
You do not integrate Omxus. You configure an OpenID Connect provider that happens to be Omxus — so if your framework already has a "Sign in with Google" path, this is the same path with a different URL.
The live provider is https://auth.omxus.com.
1. Register your site¶
A client is the provider's record of your site. Make one yourself at auth.omxus.com/developers, or by API: Registering a site. Settle two things first:
- Redirect URI — exactly where you want people sent back to, character for
character.
https://example.com/callbackdoes not matchhttps://example.com/callback/, and that is deliberate: a loose match is how someone else's URL gets into the list. - Whether your code runs in a browser. If it does, you are a public client: you get no client secret, because a browser cannot keep one. If it runs on a server, you are confidential and you get a secret.
2. Point your library at the issuer¶
Every OIDC library takes one URL and reads the rest from
/.well-known/openid-configuration.
Ask for the profile scope, and keep PKCE on: it is required for every
client, with or without a secret.
// Auth.js (NextAuth v5)
providers: [{
id: 'omxus', name: 'Omxus', type: 'oidc',
issuer: 'https://auth.omxus.com',
clientId: process.env.OMXUS_CLIENT_ID,
clientSecret: process.env.OMXUS_CLIENT_SECRET,
checks: ['pkce', 'state'],
authorization: { params: { scope: 'openid profile' } },
}]
Untested: not run against a Next.js app. A passport sample that was run against auth.omxus.com is in the Quickstart.
More framework snippets — openid-client, Authlib, Spring, Rails — are in Any app, via OIDC.
3. If your code runs in a browser¶
A browser cannot keep a secret, so register a public client (no secret) and
do the code exchange in the page. omxus-oidc.mjs does all of it:
Not served yet
omxus-oidc.mjs answers 404 at auth.omxus.com/sdk/ (checked 30 Oct
2026) and @omxus/auth is not on npm. Until it is served, use any
browser OIDC library that does the code flow with PKCE (S256).
import { createOidcClient } from 'https://auth.omxus.com/sdk/omxus-oidc.mjs';
const auth = createOidcClient({
issuer: 'https://auth.omxus.com',
clientId: 'my-site',
redirectUri: location.origin + '/callback',
});
myOwnButton.onclick = () => auth.signIn(); // your button, your styling
const { claims } = await auth.handleCallback(); // on the callback page
It makes the PKCE verifier, state and nonce, parks them in
sessionStorage, exchanges the code and checks the ID token's signature,
issuer, audience, expiry and nonce. The scope is openid profile unless you
pass scope. It renders nothing, so the button is yours.
Two more ways in, same client:
auth.signInPopup(): a small window; the page underneath never leaves. Call it from the click itself. The callback page callsfinishPopup(). A blocked popup falls back to a redirect.auth.signInSilently(): on page load, when someone is already signed in to Omxus, they arrive signed in here with no screen. A miss throws an error withsilent: true; show nothing. More: Signed in everywhere.
signIn() was run in Node against the live discovery document (30 Oct 2026):
it builds a code + S256 + state + nonce request to /oidc/authorize.
The callback half is untested from outside the auth repo.
4. What you get back¶
{
"iss": "https://auth.omxus.com",
"sub": "23cf34129785242b1ea072ec3669a3af6af2528b",
"aud": "q3V8n0bX1kZ2mH7cT9wLpA",
"iat": 1793318400,
"exp": 1793322000,
"auth_time": 1793318395,
"omxus_address": "0xc6140a760bfbc99428a8e53a08546657fad14c76"
}
sub is the person, as far as your site is concerned. It is stable for them
at your site and different at every other site, so it is a good primary key
and worthless to anyone who obtains it.
omxus_address comes only with the profile scope. It is the same at every
site, so never key your users on it. On the standard door, profile also
brings preferred_username, name and picture, and email brings the
email address. Every claim: Profiles and claims.
Limits today¶
- Refresh tokens on the standard door only. On the other doors ID and access tokens last an hour with no renewal. For a site that uses OIDC to start its own session (the normal case) this does not matter.
- No scope-by-scope consent screen. A registered client gets the claims
for the scopes it asks for. On the standard door a person's first visit to
a site needs one press on "Choose an account"; until then
prompt=noneanswersconsent_required. The operator's own first-party sites skip it. - No back-channel logout. Ending the provider session does not notify your site.