Skip to content
AXOWLDevelopers
Quickstart

Hosted login — the sign-in URL

Your app does not implement sign-in. You send people to the Axowl-hosted login page, they come back signed in. This page is the one thing you need to get right.

{portal}/login/{clientKey}?redirect_url={absolute URL to come back to}
<a href="https://login.axowl.com/login/client_e7bce279e7974411a858?redirect_url=https%3A%2F%2Fexample.com%2F">
Sign in
</a>
  • clientKey — your client’s key, client_…. Dashboard → Application. Any other value returns 404.
  • redirect_url — where the person lands after signing in. Absolute, URL-encoded. Omit it and they stay on the login page.

That is the whole contract. There is no ?app= parameter, and axowl.com/login is the Axowl console — your own organization’s sign-in, not your app’s.

HostShapeWhen
https://login.axowl.com/login/{clientKey}Default. Works immediately, no setup.
Your own domain, e.g. https://auth.example.com/ — no key in the pathAfter you verify a custom login domain. The portal resolves the client from the hostname.

Axowl runs two separate environments, each with its own portal. A client created in one does not exist in the other, so use the portal that matches the API your app talks to:

EnvironmentPortalAPIConsole
Productionhttps://login.axowl.comhttps://api.axowl.comhttps://axowl.com
Testhttps://login.test.axowl.comhttps://testapi.axowl.comhttps://test.axowl.com

The examples on this page use the production portal. For a client you created in the test console, replace login.axowl.com with login.test.axowl.com.

On a custom login domain the button is just:

<a href="https://auth.example.com/?redirect_url=https%3A%2F%2Fexample.com%2F">Sign in</a>

Everything else — providers, branding, the return trip — is identical. Social sign-in stays on the host it started from, so people never see an Axowl address.

The URL is one line in any language — the client key in the path, your callback URL-encoded in redirect_url:

const loginUrl = `https://login.axowl.com/login/${clientKey}` +
`?redirect_url=${encodeURIComponent('https://example.com/auth/callback')}`;
location.assign(loginUrl);

The return trip is covered below; with @axowl/sdk-core it is a single exchangeSessionCode(code) call.

  1. Client key is the client_… form.
  2. redirect_url is absolute, URL-encoded, and registered as a Callback URL — exact match, trailing slash included.
  3. Sign-in providers are enabled for the app (Dashboard → Login Methods), or the page shows nothing to click.
  4. Using a custom login domain? Verify it first, then drop the key from the path.
  5. New app groups start in the Development stage. There, new people cannot sign up even with “Allow public sign-up” on — only members you added or imported (up to 100 testers) can sign in, and a stranger gets error=not_public. Add testers under Dashboard → EndUser Directory, or promote the group to Production to open sign-up.

What comes back, and how to turn it into a token

Section titled “What comes back, and how to turn it into a token”

After the person signs in, the portal sends them to your redirect_url with ?code=<one-time code> appended. Exchange it once, server-side or from the browser, for the end-user JWT:

POST {apiBase}/api/public/apps/{clientKey}/auth/session/exchange
Content-Type: application/json
{ "code": "<the code from the URL>" }
{ "accessToken": "<end-user JWT>" }

The code is single-use and valid for 90 seconds; an empty code answers 400, an unknown, used or expired one 401. Store the JWT and send it as Authorization: Bearer …. With the framework-free npm package @axowl/sdk-core (always install the latest version) this is one call:

const code = new URL(location.href).searchParams.get('code');
if (code) await client.exchangeSessionCode(code); // stores the JWT; isAuthenticated() is now true

Any other stack calls the endpoint above directly — it is one fetch.

POST /api/public/apps/{clientKey}/auth/logout (Bearer = the end user’s access token) revokes the session. Send { "returnUrl": "https://yourapp.com" } to get redirectUrl back and land the person somewhere after sign-out: the URL must be listed exactly (or match an entry with a one-label host wildcard, such as https://*.myapp.pages.dev/) under Dashboard → Application → Authentication → Post-logout return URLs — the same list OIDC end_session_endpoint checks. A URL that is not listed answers 400 RETURN_URL_NOT_ALLOWED and the session is left signed in. The JS SDK wraps this as client.logout({ returnUrl }) / React signOut({ returnUrl }) and navigates to redirectUrl itself.