Sign in with Dazr Identity : documentation développeurs

Les utilisateurs peuvent déjà utiliser leur compte Google ou Microsoft dans Dazr Identity : votre application n’a donc pas besoin de boutons Google et Microsoft séparés à côté. Un bouton au lieu de trois.

Discovery et endpoints

Tout est décrit dans le document de discovery. Indiquez l’émetteur à votre bibliothèque, elle trouvera le reste.

QuoiAdresse
Émetteurhttps://identity.dazr.eu
Discoveryhttps://identity.dazr.eu/.well-known/openid-configuration
Autorisationhttps://identity.dazr.eu/oauth/authorize
Jetonhttps://identity.dazr.eu/oauth/token
Informations utilisateurhttps://identity.dazr.eu/oauth/userinfo
Clés publiques (JWKS)https://identity.dazr.eu/oauth/jwks
Révocation (RFC 7009)https://identity.dazr.eu/oauth/revoke
Introspection (RFC 7662), applications serveur web uniquementhttps://identity.dazr.eu/oauth/introspect
Déconnexion (RP-initiated logout)https://identity.dazr.eu/oauth/logout

Enregistrer une application

Guides d’intégration

Chaque stack ci-dessous utilise sa propre prise en charge standard d’OpenID Connect. Il vous faut trois valeurs de la console : l’identifiant client, le secret client (applications serveur web uniquement) et l’URI de redirection que vous avez enregistrée. Le reste vient du document de discovery.

Auth.js / NextAuth

Auth.js (NextAuth.js v5) accepte un objet fournisseur OpenID Connect personnalisé. Enregistrez une application serveur web, définissez AUTH_SECRET, AUTH_DAZR_ID et AUTH_DAZR_SECRET, et utilisez cette URL de callback comme URI de redirection : https://app.example.eu/api/auth/callback/dazr.

// auth.ts
import NextAuth from "next-auth"

export const { handlers, auth, signIn, signOut } = NextAuth({
  providers: [
    {
      id: "dazr",
      name: "Dazr Identity",
      type: "oidc",
      issuer: "https://identity.dazr.eu",
      clientId: process.env.AUTH_DAZR_ID,
      clientSecret: process.env.AUTH_DAZR_SECRET,
      authorization: { params: { scope: "openid profile email" } },
      checks: ["pkce", "state", "nonce"],
      client: { id_token_signed_response_alg: "ES256" },
    },
  ],
})

NextAuth.js v4 fonctionne de la même façon, avec type: "oauth" et l’URL de discovery :

// pages/api/auth/[...nextauth].ts (NextAuth.js v4), in providers: [ ... ]
{
  id: "dazr",
  name: "Dazr Identity",
  type: "oauth",
  wellKnown: "https://identity.dazr.eu/.well-known/openid-configuration",
  clientId: process.env.DAZR_CLIENT_ID,
  clientSecret: process.env.DAZR_CLIENT_SECRET,
  authorization: { params: { scope: "openid profile email" } },
  idToken: true,
  checks: ["pkce", "state"],
  client: { id_token_signed_response_alg: "ES256" },
  profile(profile) {
    return { id: profile.sub, name: profile.name ?? null, email: profile.email }
  },
}

Next.js App Router

Avec le fichier auth.ts ci-dessus, ajoutez le route handler et un bouton de connexion qui exécute une server action.

// app/api/auth/[...nextauth]/route.ts
import { handlers } from "@/auth"
export const { GET, POST } = handlers

// app/page.tsx
import { auth, signIn, signOut } from "@/auth"

export default async function Page() {
  const session = await auth()
  if (session?.user) {
    return (
      <form action={async () => { "use server"; await signOut() }}>
        <p>Signed in as {session.user.email}</p>
        <button type="submit">Sign out</button>
      </form>
    )
  }
  return (
    <form action={async () => { "use server"; await signIn("dazr") }}>
      <button type="submit" className="dazr-signin">Sign in with Dazr Identity</button>
    </form>
  )
}

Donnez au bouton le style présenté dans Le bouton. Dans les callbacks, le sub Dazr est account.providerAccountId.

WordPress

Utilisez une extension cliente OpenID Connect générique, comme OpenID Connect Generic Client. Enregistrez une application serveur web et remplissez les réglages de l’extension avec les valeurs ci-dessous. L’extension affiche l’URI de redirection à enregistrer sur sa page de réglages ; par défaut, c’est https://example.com/wp-admin/admin-ajax.php?action=openid-connect-authorize.

RéglageValeur
Identifiant clientvotre identifiant client
Secret clientvotre secret client
Scopeopenid profile email
Endpoint de connexion (autorisation)https://identity.dazr.eu/oauth/authorize
Endpoint de jetonshttps://identity.dazr.eu/oauth/token
Endpoint userinfohttps://identity.dazr.eu/oauth/userinfo
Endpoint de fin de sessionhttps://identity.dazr.eu/oauth/logout
Identity key (clé d’identité)sub
PKCEactivé (S256)

Les noms des réglages varient un peu d’une extension à l’autre. Si une extension n’a pas d’option PKCE, choisissez-en une autre : Dazr Identity refuse les connexions sans PKCE.

Laravel

Laravel Socialite n’a pas de pilote OpenID Connect générique intégré : ajoutez donc un petit pilote personnalisé. Il envoie les personnes vers Dazr avec PKCE et lit l’utilisateur sur l’endpoint userinfo. Socialite ne lit pas le document de discovery, les endpoints sont donc écrits en clair. Enregistrez une application serveur web avec l’URI de redirection https://app.example.eu/auth/dazr/callback.

<?php
// app/Socialite/DazrProvider.php
namespace App\Socialite;

use Laravel\Socialite\Two\AbstractProvider;
use Laravel\Socialite\Two\User;

class DazrProvider extends AbstractProvider
{
    protected $scopes = ['openid', 'profile', 'email'];
    protected $scopeSeparator = ' ';
    protected $usesPKCE = true;

    protected function getAuthUrl($state)
    {
        return $this->buildAuthUrlFromBase('https://identity.dazr.eu/oauth/authorize', $state);
    }

    protected function getTokenUrl()
    {
        return 'https://identity.dazr.eu/oauth/token';
    }

    protected function getUserByToken($token)
    {
        $response = $this->getHttpClient()->get('https://identity.dazr.eu/oauth/userinfo', [
            'headers' => ['Authorization' => 'Bearer '.$token],
        ]);

        return json_decode((string) $response->getBody(), true);
    }

    protected function mapUserToObject(array $user)
    {
        return (new User)->setRaw($user)->map([
            'id' => $user['sub'],
            'name' => $user['name'] ?? null,
            'email' => $user['email'] ?? null,
        ]);
    }
}
// config/services.php
'dazr' => [
    'client_id' => env('DAZR_CLIENT_ID'),
    'client_secret' => env('DAZR_CLIENT_SECRET'),
    'redirect' => env('DAZR_REDIRECT_URI'),
],

// app/Providers/AppServiceProvider.php, in boot()
use Laravel\Socialite\Facades\Socialite;
use App\Socialite\DazrProvider;

Socialite::extend('dazr', function ($app) {
    return Socialite::buildProvider(DazrProvider::class, config('services.dazr'));
});

// routes/web.php
Route::get('/auth/dazr', fn () => Socialite::driver('dazr')->redirect());
Route::get('/auth/dazr/callback', function () {
    $dazr = Socialite::driver('dazr')->user();
    $user = \App\Models\User::updateOrCreate(
        ['dazr_sub' => $dazr->getId()],
        ['name' => $dazr->getName() ?? $dazr->getEmail(), 'email' => $dazr->getEmail()],
    );
    Auth::login($user);
    return redirect('/');
});

Supabase

Supabase Auth n’a pas de fournisseur OpenID Connect générique que l’on peut pointer vers n’importe quel émetteur : ses fournisseurs de connexion et ses intégrations d’authentification tierces sont des listes fixes. Vous ne pouvez donc pas ajouter Dazr Identity dans le tableau de bord Supabase aujourd’hui. Si Supabase ajoute la prise en charge générique d’OpenID Connect, utilisez les valeurs de la liste ci-dessous.

L’alternative : connectez les personnes avec Dazr Identity sur votre propre serveur (avec l’un des guides de cette page), enregistrez le sub Dazr dans votre table des utilisateurs et parlez à Supabase depuis ce serveur avec la clé service role, en contrôlant les accès dans votre propre code. N’envoyez jamais la clé service role à un navigateur.

Django

Utilisez mozilla-django-oidc. Enregistrez une application serveur web avec l’URI de redirection https://app.example.eu/oidc/callback/. La bibliothèque ne lit pas le document de discovery, les endpoints sont donc écrits en clair.

# settings.py
import os

INSTALLED_APPS += ["mozilla_django_oidc"]  # after django.contrib.auth
AUTHENTICATION_BACKENDS = [
    "mozilla_django_oidc.auth.OIDCAuthenticationBackend",
    "django.contrib.auth.backends.ModelBackend",
]

OIDC_RP_CLIENT_ID = os.environ["DAZR_CLIENT_ID"]
OIDC_RP_CLIENT_SECRET = os.environ["DAZR_CLIENT_SECRET"]
OIDC_RP_SCOPES = "openid profile email"
OIDC_RP_SIGN_ALGO = "ES256"
OIDC_OP_JWKS_ENDPOINT = "https://identity.dazr.eu/oauth/jwks"
OIDC_OP_AUTHORIZATION_ENDPOINT = "https://identity.dazr.eu/oauth/authorize"
OIDC_OP_TOKEN_ENDPOINT = "https://identity.dazr.eu/oauth/token"
OIDC_OP_USER_ENDPOINT = "https://identity.dazr.eu/oauth/userinfo"
OIDC_USE_PKCE = True
OIDC_PKCE_CODE_CHALLENGE_METHOD = "S256"

LOGIN_REDIRECT_URL = "/"
LOGOUT_REDIRECT_URL = "/"

# urls.py
from django.urls import include, path
urlpatterns += [path("oidc/", include("mozilla_django_oidc.urls"))]

# template: start the sign-in
# <a href="{% url 'oidc_authentication_init' %}">Sign in with Dazr Identity</a>

Par défaut, le backend associe les utilisateurs par e-mail. Pour associer les comptes à sub, créez une sous-classe de OIDCAuthenticationBackend et redéfinissez filter_users_by_claims et create_user. Utilisez une version récente : les anciennes versions ne vérifient pas les signatures ES256.

Node.js (openid-client)

openid-client (version 6) lit le document de discovery et vérifie pour vous PKCE, state, nonce et le jeton d’identité.

import * as client from 'openid-client';

const config = await client.discovery(
  new URL('https://identity.dazr.eu'),
  process.env.DAZR_CLIENT_ID,
  process.env.DAZR_CLIENT_SECRET, // public client: pass undefined here and client.None() as the 4th argument
);
const redirect_uri = 'https://app.example.eu/auth/dazr/callback';

// 1. Start: keep the three random values in the user's session.
export async function start(session) {
  session.verifier = client.randomPKCECodeVerifier();
  session.state = client.randomState();
  session.nonce = client.randomNonce();
  return client.buildAuthorizationUrl(config, {
    redirect_uri,
    scope: 'openid profile email',
    code_challenge: await client.calculatePKCECodeChallenge(session.verifier),
    code_challenge_method: 'S256',
    state: session.state,
    nonce: session.nonce,
  });
}

// 2. Callback: pass the full callback URL (a URL object).
export async function callback(session, currentUrl) {
  const tokens = await client.authorizationCodeGrant(config, currentUrl, {
    pkceCodeVerifier: session.verifier,
    expectedState: session.state,
    expectedNonce: session.nonce,
  });
  const claims = tokens.claims(); // sub, email, name
  return { sub: claims.sub, email: claims.email, name: claims.name };
}

Toute bibliothèque OpenID Connect

Si votre stack n’est pas listée, tout client OpenID Connect fonctionne. Vérifiez ces réglages :

Le flux

  1. Créez un code_verifier aléatoire (43 à 128 caractères) et son code_challenge = base64url(SHA-256(verifier)). Créez un state et un nonce aléatoires. Gardez les trois dans la session de l’utilisateur.
  2. Redirigez vers l’endpoint d’autorisation avec response_type=code, client_id, redirect_uri, scope (toujours avec openid), state, nonce, code_challenge et code_challenge_method=S256.
  3. La personne se connecte si nécessaire et voit l’écran de consentement avec les données réelles. Si elle accepte, elle revient sur votre URI de redirection avec code, state et iss. Vérifiez que state correspond et que iss vaut https://identity.dazr.eu.
  4. Sur votre serveur, envoyez un POST à l’endpoint de jetons avec grant_type=authorization_code, code, le même redirect_uri et le code_verifier.
  5. Vérifiez le jeton d’identité : signature ES256 avec une clé du JWKS (selon le kid), iss, aud = votre identifiant client, exp et votre nonce. Utilisez sub comme clé du compte.

Le paramètre prompt accepte none (réponse immédiate avec login_required ou consent_required si la personne devait agir), login (demander à la personne de se reconnecter) et consent (afficher l’écran de consentement même s’il a déjà été accepté). max_age est pris en charge. Consentement mémorisé : si la personne a déjà approuvé les mêmes scopes, elle revient directement à votre application. Si vous en demandez davantage plus tard, l’écran de consentement n’affiche que ce qui est nouveau.

Scopes et claims

Ne demandez que ce dont vous avez besoin. Rien n’existe en dehors de ce tableau : pas de contacts, pas de fichiers, pas de mots de passe.

ScopeClaims
openid (obligatoire)sub : un identifiant aléatoire pour la personne, identique pour toutes les applications de votre organisation et différent pour toute autre organisation
profilename (s’il est renseigné) et locale
emailemail et email_verified (toujours true)
addressaddress (formatted, street_address, locality, region, postal_code, country), seulement si la personne en a enregistré une
organisationsorganisations : les organisations que la personne coche sur l’écran de consentement, chacune avec id, name, country, register_number, vat, vat_verified (true uniquement si le service européen VIES a confirmé le numéro de TVA), verified, verification (voir Organisations vérifiées) et role
offline_accessaucun claim ; vous recevez aussi un jeton de rafraîchissement

Les claims figurent dans le jeton d’identité pour les scopes approuvés par la personne. L’endpoint d’informations utilisateur renvoie le même ensemble, avec les valeurs actuelles.

Organisations vérifiées

Dazr vérifie une organisation quand son dirigeant, ou une autre personne habilitée à signer pour elle, signe une courte déclaration avec une signature électronique qualifiée (QES). C’est instantané et cela fonctionne dans tous les pays de l’UE. Sans signature qualifiée, le représentant peut envoyer à la place un extrait du registre du commerce et une pièce d’identité ; Dazr les examine à la main. Chaque organisation de la claim organisations porte sa vérification actuelle :

verification.statusSignification
unverifiedNon vérifiée, ou une vérification a échoué, expiré ou a été révoquée (par exemple après un changement de dénomination ou de numéro d’immatriculation).
pendingLa vérification est en cours : le représentant a été invité à signer, ou Dazr examine des documents.
verifiedVérifiée. method vaut qes, qes_org (le certificat lui-même désigne l’organisation, par numéro de TVA ou d’immatriculation), documents ou extract, et verified_at est un temps Unix.

Le booléen verified reste pour la compatibilité et vaut verification.status === 'verified'. Chaque organisation a aussi un id, le même que dans les webhooks.

"organisations": [{
  "id": "org_3k9x2m0q8w1v5t7a", "name": "Conti Logistica S.r.l.", "country": "IT",
  "register_number": "REA MI1234567", "vat": "IT12345678903", "vat_verified": true,
  "verified": false, "verification": { "status": "pending", "method": "qes" }, "role": "owner"
}]

Exiger une organisation vérifiée

Dans la console, réglez Exiger une organisation vérifiée sur Vérification commencée ou Vérifiée, ou demandez-le par requête avec acr_values=urn:dazr:org:verification-started ou acr_values=urn:dazr:org:verified (la plus stricte des deux s’applique). Votre application doit aussi demander le scope organisations.

Une personne sans organisation éligible la complète dans la même connexion : son nom, l’organisation (avec le numéro de TVA vérifié dans VIES), puis la vérification. Elle peut signer tout de suite, se faire envoyer la déclaration par e-mail ou désigner une autre personne qui signe. Elle coche ensuite l’organisation sur l’écran de consentement (seules les organisations éligibles peuvent être cochées) et revient à votre URI de redirection.

Si quelqu’un d’autre doit encore signer, la personne revient avec le statut pending, même si vous avez demandé Vérifiée : vous recevez un code, la claim indique pending et l’acr de l’ID token vaut urn:dazr:org:verification-started au lieu de urn:dazr:org:verified. Décidez toujours selon verification.status, jamais selon la réussite de la connexion. Avec prompt=none, vous recevez interaction_required si l’exigence n’est pas remplie.

Les changements du réglage s’appliquent dès la prochaine connexion. Les personnes déjà connectées ne sont pas déconnectées : les réponses de refresh, l’endpoint userinfo et les webhooks portent toujours le statut actuel, utilisez-les donc pour les sessions existantes.

Webhooks

Ajoutez une URL de webhook (https) dans la console. Vous voyez le secret de signature une seule fois ; vous pouvez le renouveler. Dazr envoie organisation.verification.updated quand une organisation qu’un de vos utilisateurs a partagée avec votre application passe à pending, verified, failed ou unverified. Les applications qui n’ont jamais reçu une organisation par consentement n’en entendent jamais parler.

POST /your/webhook
Content-Type: application/json
Dazr-Event: organisation.verification.updated
Dazr-Delivery: dlv_8Fq2…
Dazr-Signature: t=1791021600,v1=5e0c…

{ "id": "evt_…", "type": "organisation.verification.updated", "created": 1791021600,
  "data": { "organisation": { "id": "org_3k9x2m0q8w1v5t7a", "name": "Conti Logistica S.r.l.", "country": "IT" },
            "status": "verified", "method": "qes_org", "verified_at": 1791021598,
            "subjects": ["Xo1c…"] } }

status vaut pending, verified, failed ou unverified. subjects sont les valeurs sub, dans votre application, des personnes qui lui ont partagé cette organisation. Vérifiez la signature avant de faire confiance au contenu :

import crypto from 'node:crypto';
// raw = the request body exactly as received (a string), header = the Dazr-Signature header
function verifyDazrSignature(raw, header, secret) {
  const m = /^t=(\d+),v1=([a-f0-9]{64})$/.exec(header || '');
  if (!m || Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false; // reject old deliveries
  const want = crypto.createHmac('sha256', secret).update(m[1] + '.' + raw).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(want), Buffer.from(m[2]));
}

Répondez par un 2xx en moins de 8 secondes. Sinon, Dazr réessaie après environ 5 minutes, 30 minutes, 2, 6, 12 et 24 heures, puis marque l’envoi comme échoué. Chaque tentative porte le même ID Dazr-Delivery : ignorez les doublons. La console liste les envois récents, peut en renvoyer un et peut envoyer un événement de test (webhook.test). Interroger régulièrement l’endpoint userinfo fonctionne aussi.

Jetons et durées

JetonDurée et règles
Code d’autorisation60 secondes, usage unique, lié à votre client, à l’URI de redirection et au challenge PKCE. Utiliser un code deux fois révoque les jetons qu’il a émis.
Jeton d’accès10 minutes. Un JWT signé (ES256, typ at+jwt) avec aud = votre identifiant client. Envoyez-le en Authorization: Bearer.
Jeton d’identité10 minutes. ES256, avec iss, sub, aud, exp, iat, auth_time, nonce et amr si connu.
Jeton de rafraîchissementUniquement avec offline_access. Change à chaque utilisation : enregistrez toujours le nouveau. Renvoyer un ancien jeton de rafraîchissement révoque toute la connexion. Expire après 30 jours sans utilisation et au plus tard après 180 jours.

Les clés de signature changent. Choisissez toujours la clé d’après le kid dans le JWKS et rechargez le JWKS lorsque vous voyez un kid inconnu.

Erreurs

Tant que votre identifiant client et votre URI de redirection sont valides, les erreurs reviennent sur votre URI de redirection sous la forme error, error_description, state et iss : par exemple invalid_request (comme un PKCE absent ou plain), invalid_scope, unsupported_response_type, access_denied (la personne a annulé, ou l’application est en test et la personne n’est pas membre), login_required, consent_required et interaction_required (avec prompt=none, quand une organisation vérifiée exigée manque). Avec un client inconnu ou une URI de redirection non enregistrée, Dazr affiche une page d’erreur et ne redirige jamais. L’endpoint de jetons répond par des erreurs JSON comme invalid_client, invalid_grant et unsupported_grant_type.

Déconnexion

Pour déconnecter quelqu’un, envoyez la personne vers l’endpoint de déconnexion avec id_token_hint (ou client_id), un post_logout_redirect_uri facultatif enregistré dans les paramètres de l’application, et state. Dazr lui demande si elle veut aussi se déconnecter de Dazr Identity sur cet appareil, puis la renvoie. Révoquez à l’endpoint de révocation les jetons de rafraîchissement dont vous n’avez plus besoin.

Test et mise en ligne

Une nouvelle application est en test : seuls les membres de votre organisation peuvent se connecter, et l’écran de consentement l’indique. Pour la mettre en ligne, faites vérifier votre organisation dans Dazr Identity, ajoutez une URI de redirection https:// et demandez un examen dans la console. Modifier le nom, la finalité, la politique de confidentialité ou les données d’une application en ligne nécessite un nouvel examen.

Le bouton

Utilisez le texte « Sign in with Dazr Identity » et le logo Dazr comme ci-dessous. Vous pouvez changer la taille, mais pas le logo, les couleurs ni le texte. Faites-le pointer vers votre propre route qui lance le flux.

<a href="/auth/dazr" style="display:inline-flex;align-items:center;gap:10px;height:44px;padding:0 18px;border-radius:22px;background:#18203a;color:#fff;font:600 15px/1 system-ui,sans-serif;text-decoration:none">
  <svg width="20" height="20" viewBox="0 0 100 100" aria-hidden="true"><path d="M50 4 89 16v31c0 25.5-16.8 42.5-39 50C27.8 89.5 11 72.5 11 47V16z" fill="#fff"/><path d="M50 15.5 79 24.5v22.8c0 19.5-12.4 32.6-29 38.7C33.4 79.9 21 66.8 21 47.3V24.5z" fill="#18203a"/><path d="M50 24 71 30.6v16.9c0 14.5-9 24.4-21 29.2-12-4.8-21-14.7-21-29.2V30.6z" fill="#fff"/></svg>
  Sign in with Dazr Identity
</a>

Un exemple minimal en Node.js

Node 18 ou plus récent, sans dépendances. Une application serveur web avec secret client ; pour un client public, supprimez l’en-tête Authorization et envoyez client_id dans le corps.

import crypto from 'node:crypto';
const issuer = 'https://identity.dazr.eu';
const clientId = process.env.DAZR_CLIENT_ID;
const clientSecret = process.env.DAZR_CLIENT_SECRET;
const redirectUri = 'https://app.example.eu/auth/dazr/callback';
const b64url = (buf) => Buffer.from(buf).toString('base64url');

// 1. Start: keep verifier, state and nonce in the user's session.
export function start(session) {
  session.verifier = b64url(crypto.randomBytes(32));
  session.state = b64url(crypto.randomBytes(16));
  session.nonce = b64url(crypto.randomBytes(16));
  const challenge = b64url(crypto.createHash('sha256').update(session.verifier).digest());
  return issuer + '/oauth/authorize?' + new URLSearchParams({
    response_type: 'code', client_id: clientId, redirect_uri: redirectUri,
    scope: 'openid profile email', state: session.state, nonce: session.nonce,
    code_challenge: challenge, code_challenge_method: 'S256',
  });
}

// 2. Callback: check state, exchange the code, verify the ID token.
export async function callback(session, query) {
  if (query.error) throw new Error('sign-in failed: ' + query.error);
  if (query.state !== session.state || query.iss !== issuer) throw new Error('state or issuer mismatch');
  const res = await fetch(issuer + '/oauth/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      Authorization: 'Basic ' + Buffer.from(clientId + ':' + clientSecret).toString('base64'),
    },
    body: new URLSearchParams({ grant_type: 'authorization_code', code: query.code, redirect_uri: redirectUri, code_verifier: session.verifier }),
  });
  const tokens = await res.json();
  if (!res.ok) throw new Error(tokens.error);
  const claims = await verifyIdToken(tokens.id_token, session.nonce);
  return { sub: claims.sub, email: claims.email, name: claims.name, tokens };
}

async function verifyIdToken(idToken, nonce) {
  const [h, p, s] = idToken.split('.');
  const header = JSON.parse(Buffer.from(h, 'base64url'));
  const { keys } = await (await fetch(issuer + '/oauth/jwks')).json();
  const jwk = keys.find((k) => k.kid === header.kid);
  if (!jwk || header.alg !== 'ES256') throw new Error('unknown signing key');
  const ok = crypto.verify('sha256', Buffer.from(h + '.' + p),
    { key: crypto.createPublicKey({ key: jwk, format: 'jwk' }), dsaEncoding: 'ieee-p1363' }, Buffer.from(s, 'base64url'));
  const c = JSON.parse(Buffer.from(p, 'base64url'));
  const now = Math.floor(Date.now() / 1000);
  if (!ok || c.iss !== issuer || c.aud !== clientId || c.exp < now - 30 || c.nonce !== nonce) throw new Error('invalid ID token');
  return c;
}

Limites

Les endpoints d’autorisation et de jetons sont limités en débit. Si vous recevez une erreur HTTP 429, attendez puis réessayez ; ne réessayez pas en boucle rapide.

Vos obligations

Votre organisation est responsable de traitement indépendant pour les données qu’elle reçoit. Les Conditions développeurs de Dazr Identity précisent ce que vous pouvez en faire, comment les protéger et comment signaler les violations. Questions : hello@dazr.eu.