Integration Guide

How to add authentication to your app using this identity service.

Overview

This service implements the OAuth 2.0 Authorization Code Flow with OpenID Connect (OIDC) on top. Your app redirects users to a hosted login page, receives an authorization code, exchanges it for tokens, and then calls the userinfo endpoint to get the authenticated user's profile.

1. User clicks "Login" in your app
2. Redirect to: https://auth.svc.jxs.se/login/{appSlug}?redirect_uri=...&client_id=...&state=...
3. User logs in / registers
4. Auth service redirects to: your redirect_uri?code=xxx&state=xxx
5. Your server POSTs to: https://auth.svc.jxs.se/api/auth/token
6. You receive access_token + id_token
7. Call https://auth.svc.jxs.se/api/auth/userinfo to get user profile

1. Create an Application

  1. Go to the Admin Panel → Applications → New Application
  2. Enter your app name and redirect URI (e.g. https://yourapp.example.com/auth/callback)
  3. Choose which login methods to enable (Password, Google, GitHub, Microsoft)
  4. Save — you'll receive a Client ID and Client Secret

2. Initiate Login

Redirect the user to the login page with these query parameters:

const state = crypto.randomUUID()
// Store state in session cookie to prevent CSRF

const params = new URLSearchParams({
  client_id: 'your-client-id',
  redirect_uri: 'https://yourapp.com/auth/callback',
  state,
  response_type: 'code',
  scope: 'openid profile email',
})

// Redirect user to:
// https://auth.svc.jxs.se/login/{appSlug}?{params}

Replace {appSlug} with your application's slug from the admin panel.

3. Handle the Callback

Your redirect URI receives ?code=xxx&state=xxx. Verify the state, then exchange the code for tokens on your server:

// Node.js / Next.js server-side example
const response = await fetch('https://auth.svc.jxs.se/api/auth/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    grant_type: 'authorization_code',
    code: searchParams.get('code'),
    redirect_uri: 'https://yourapp.com/auth/callback',
    client_id: process.env.AUTH_CLIENT_ID,
    client_secret: process.env.AUTH_CLIENT_SECRET,
  }),
})

const { access_token, id_token } = await response.json()
⚠️ Always exchange the code server-side. Never expose your client_secret to the browser.

4. Get User Profile

Use the access token to fetch the authenticated user's profile:

const profile = await fetch('https://auth.svc.jxs.se/api/auth/userinfo', {
  headers: { Authorization: `Bearer ${access_token}` },
}).then(r => r.json())

// profile = {
//   sub: "user-id",
//   email: "user@example.com",
//   name: "User Name",
//   email_verified: true
// }

Environment Variables

AUTH_SERVICE_URL=https://auth.svc.jxs.se
AUTH_CLIENT_ID=your-client-id        # from admin panel
AUTH_CLIENT_SECRET=your-secret       # from admin panel
AUTH_REDIRECT_URI=https://yourapp.com/auth/callback
AUTH_APP_SLUG=your-app-slug          # your app's slug

API Reference

GET/login/{appSlug}

Hosted login page for your application. Accepts redirect_uri, client_id, state, scope.

POST/api/auth/app-register

Register a new user and get an authorization code. Body: { email, password, name, applicationId, redirect_uri }

POST/api/auth/token

Exchange authorization code for access_token + id_token. Body: { grant_type, code, redirect_uri, client_id, client_secret }

GET/api/auth/userinfo

Get authenticated user profile. Requires Authorization: Bearer {access_token}

GET/.well-known/openid-configuration

OIDC discovery document with all endpoint URLs.

Working Example

A live demo app is deployed at testapp.app.jxs.se — it has a login button, secure dashboard, and logout. The source is at ~/workspace/test-app/.

Try the test app login page →