Skip to Content
ConceptsAuthentication

Authentication

The SDK authenticates every request to the Slade ID backend with a bearer token. This page explains whose identity that token represents and the one integration piece you must provide: a token endpoint on your own backend.

The identity model: you authenticate as the integrator, not the end user

This is the single most important thing to understand.

The SDK is embedded in your application, and your application already has its own users and its own authentication. Slade ID does not know about those users. The identity Slade ID cares about is your organisation. Every biometric call is attributed to that integrator, regardless of which of your end users triggered it.

The OAuth invariant you can’t design around

A machine identity is a confidential client: it is proven with a client secret. And a browser cannot keep a secret; anything shipped to the browser is readable by anyone who opens dev tools or the network tab.

Therefore:

A confidential identity must be exchanged for a token by a trusted, server-side component. There is no secure, browser-only way to authenticate as a machine identity. This is inherent to OAuth, not a Slade ID limitation.

The adopted flow: a backend token broker

Your backend holds the Slade ID client credentials, performs the OAuth2 client_credentials exchange with the auth provider, and returns a short-lived access token to your frontend. The SDK consumes that token.

End user ──(already signed in to your app)──▶ Your frontend │ (Slade ID SDK embedded here) │ GET /your-backend/sladeid-token (gated by your session) Your backend ── holds SLADEID_CLIENT_SECRET │ ── POST client_credentials ▶ Slade ID Keycloak short-lived access token ──▶ SDK (via tokenProvider) SDK ` uses <token>` ──▶ Slade ID backend

1. Add a token endpoint to your backend

Node / Express

// Behind your app's existing auth middleware. The secret stays on the server. app.get('/api/sladeid-token', requireSession, async (req, res) => { const resp = await fetch( `${AUTH_BASE_URL}/realms/slade360/protocol/openid-connect/token`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ grant_type: 'client_credentials', client_id: process.env.SLADEID_CLIENT_ID, client_secret: process.env.SLADEID_CLIENT_SECRET, }), }, ); if (!resp.ok) return res.status(502).json({ error: 'token exchange failed' }); const { access_token, expires_in } = await resp.json(); res.json({ access_token, expires_in }); });

Python / Django

import os, requests from rest_framework.decorators import api_view, permission_classes from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response @api_view(["GET"]) @permission_classes([IsAuthenticated]) # your app's session/auth def sladeid_token(request): r = requests.post( f"{os.environ['AUTH_BASE_URL']}/realms/slade360/protocol/openid-connect/token", data={ "grant_type": "client_credentials", "client_id": os.environ["SLADEID_CLIENT_ID"], "client_secret": os.environ["SLADEID_CLIENT_SECRET"], }, timeout=15, ) r.raise_for_status() body = r.json() return Response({"access_token": body["access_token"], "expires_in": body["expires_in"]})

2. Feed the token to the SDK with tokenProvider

The SDK stays authentication-agnostic. Give it a getToken callback that returns a current token; the SDK caches it and calls the callback again whenever the backend rejects the token with a 401 (so it self-heals on expiry).

import { SladeID } from '@sladeid/slade-id-sdk'; const sdk = new SladeID({ middlewareUrl: 'https://api.biometrics-dev.slade360.co.ke/', auth: { type: 'tokenProvider', getToken: async () => { const res = await fetch('/api/sladeid-token', { credentials: 'include' }); const { access_token } = await res.json(); return access_token; }, }, });

That is the whole integration. Everything below is optional context.

Token lifetime

Keep tokens short-lived. Because getToken() is re-invoked on a 401, the SDK recovers from expiry automatically; you do not need long-lived tokens, and you should avoid them: a token that reaches the browser is exposed for its entire lifetime if it leaks. Prefer having your endpoint return a fresh short-lived token and let the SDK refresh on demand. If you cache tokens in your backend, cache to just under expires_in.

Preserving the end user’s identity (optional): RFC 8693 token exchange

The broker above attributes every call to the integrator. If you need the Slade ID token to also carry which of your users acted (for finer attribution or SSO), have the same backend endpoint perform an RFC 8693 token exchange : swap the user’s token from your IdP for a Slade ID token, instead of a plain client_credentials grant. This requires Slade ID’s Keycloak to federate/trust your IdP and is more setup — adopt it only if per-user attribution is a requirement. The SDK side is unchanged: it still just consumes the token via tokenProvider.

For per-operation attribution without full token exchange, you can also pass an agentId on capture - see the API reference.