Skip to main content
Developer Documentation

Build with OneTimeLogin

From zero to your first SSO login — most partners onboard within a few hours of receiving keys.

QUICKSTART

Get a 200 from /api/auth/login with typical guided setup

Follow these five steps in order. By the end, your app will be receiving real OneTimeLogin access tokens.

  1. 1

    Register your site

    Create a business account and add your site. This unlocks the API console where your keys live.

    Register your site
  2. 2

    Grab your API key

    After registration, your Site Key is shown once on the dashboard at Dashboard → Settings → API Keys. Store it in your server-side secret manager — never commit it.

  3. 3

    Configure your callback URL

    Tell OneTimeLogin where to redirect users after a successful login. Set it under Settings → Callback URL. Use HTTPS in production. Localhost is allowed in dev.

  4. 4

    Test login with code

    Pick your stack and run the snippet. Replace YOUR_SITE_KEY with the key from Step 2.

    curl -X POST https://api.onetimelogin.com/api/auth/login \
      -H "Content-Type: application/json" \
      -H "X-OTL-Site-Key: YOUR_SITE_KEY" \
      -d '{"email":"user@example.com","password":"REDACTED"}'
    const res = await fetch('https://api.onetimelogin.com/api/auth/login', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-OTL-Site-Key': process.env.OTL_SITE_KEY,
      },
      body: JSON.stringify({ email, password }),
    });
    const data = await res.json();
    // data.access_token + data.refresh_token
    import requests
    res = requests.post(
        'https://api.onetimelogin.com/api/auth/login',
        headers={
            'Content-Type': 'application/json',
            'X-OTL-Site-Key': OTL_SITE_KEY,
        },
        json={'email': email, 'password': password},
    )
    data = res.json()
    # data['access_token'] + data['refresh_token']
  5. 5

    Verify the response

    A successful login returns HTTP 200 and a payload like this:

    {
      "access_token": "<jwt>",
      "refresh_token": "<opaque>",
      "token_type": "Bearer",
      "expires_in": 1800,
      "user": {
        "id": "01HKZ...",
        "email": "user@example.com",
        "name": "Jane Doe"
      }
    }

    Send access_token on every authenticated call as Authorization: Bearer <access_token>.

You just authenticated a user via OneTimeLogin.

Want help with production rollout, custom roles, or bulk migration? Talk to a human.

Book a 20-min call

Need to revoke a token? See Sessions. Building a webhook receiver? See Events. Want SAML instead? See Enterprise SSO.

What you can build

Three of the most common integrations.

SSO sign-in flow

Drop OneTimeLogin in front of any login screen. One registration, every connected partner site.

Read guide →

Bulk user registration

Migrate from your existing user table with a CSV. Onboard thousands without resetting passwords.

Read guide →

Network-wide profile sync

When a user updates their profile on one partner site, every other site sees the change instantly via webhook.

Read guide →

SDKs & libraries

The HTTP API works from any language. We also publish thin wrappers for the common ones.

Node.js / TypeScript

npm install @onetimelogin/sdk

Full types, retry, refresh-token rotation built in.

Python

pip install onetimelogin

Sync + async clients, Pydantic models, FastAPI helper.

Need Go, Ruby, or PHP? See the raw HTTP API — and let us know what to build next at developers@onetimelogin.com.

Sessions & tokens

  • Access token: short-lived JWT, 30 minutes. Send as Authorization: Bearer <access_token>.
  • Refresh token: opaque string, 30 days. Exchange for a new access token at POST /api/auth/refresh.
  • Revoke: POST /api/auth/logout revokes the current session. DELETE /api/sessions/{id} revokes a specific one. Bumps the user's Session Version.
  • Storage: store access tokens in sessionStorage, refresh tokens in HttpOnly cookies. Never localStorage.

Full schema in the Sessions API reference. For force-logout-everywhere flows, see Events → session.revoked.

Webhook events

We POST to your registered URL whenever something happens. Verify X-OTL-Signature (HMAC-SHA256) before processing.

Event Fires when
user.createdA new user registers anywhere in the network.
user.updatedProfile fields change on any partner site.
session.createdA user logs in to one of your sites.
session.revokedA session is logged out or admin-revoked.
role.assignedA user is granted a role on your site.
payment.completedA paid plan order is fulfilled.

Retries: up to 5 with exponential backoff. See full payloads in the API webhooks reference. Need to test locally? See the webhooks reference.

Error codes

Every error response is JSON: {"detail": "<message>", "request_id": "<uuid>"}. Always log request_id — we use it to find the matching server log when you write to support.

Code Meaning Action
400Bad requestCheck the field listed in detail.
401UnauthenticatedToken missing, expired, or revoked. Refresh.
403ForbiddenToken is valid but lacks the role for this resource.
404Not foundResource ID is wrong, or it belongs to a different site.
409ConflictDuplicate email on register, version mismatch on update.
422Validation errorBody parsed, but a field failed validation. See detail.
429Rate limitedHonor Retry-After.
5xxServer errorRetry with backoff. Page status: /status.

Enterprise SSO (SAML / OIDC)

OneTimeLogin can sit in front of Okta, Azure AD, or any SAML 2.0 / OIDC IdP. Your end users get the network experience; their IT keeps central control.

  • Just-in-time provisioning — we create the user on first login.
  • SCIM 2.0 user/group sync (Pro plan).
  • Per-domain forced SSO — e.g. all @acme.com users must use SAML.

Setup is 30 min with a metadata XML or OIDC discovery URL. Email us to start.

FAQ

Do I have to migrate my existing user passwords?

No. Bulk import accepts your existing bcrypt / argon2 / scrypt hashes. Users keep their current password — first login auto-rehashes to our parameters. See Bulk registration.

Where is data stored? Is it GDPR / SOC 2?

EU and US regions. SOC 2 Type II audit underway; target completion Q4 2026. GDPR-aligned with DPA available on request. Full posture on the Security page.

Can a user belong to many partner sites with one account?

Yes — that is the point. The user registers once and chooses which sites in the Network to authorize. Each site sees only the fields the user grants it.

What happens if your service is down?

Existing access tokens stay valid for their full 30-minute lifetime — your app keeps serving authenticated users. Live status: status.onetimelogin.com.

Glossary

API key
The long-lived secret your server uses for site-level operations. Distinct from a user's access token.
Site Key
The public identifier for one registered site. Sent in X-OTL-Site-Key. Safe to expose in server-side code; never in browser code.
Access Token
Short-lived (30 min) signed JWT representing one user's session.
Refresh Token
Opaque, long-lived (30 day) credential used to mint new access tokens without re-auth.
Session Version
Integer stamped into every access token. Bumping it (e.g. on password change) invalidates every existing token in one move.
Webhook Event
A signed POST to your registered URL when something happens — user.created, session.revoked, etc.
Network
The set of all partner sites a user has authorized. One identity, many sites.
Partner Site
Any site that has registered with OneTimeLogin and accepts our access tokens.

API reference

Every endpoint, every parameter, every response code — with copyable examples.

Open API reference