Sign in with Dazr Identity: Entwicklerdokumentation
Standard-OpenID-Connect 1.0 mit dem Authorization Code Flow und PKCE. Kein SDK nötig: Jede zertifizierte OpenID-Connect-Bibliothek funktioniert, und eigener Code auch.
Menschen können ihr Google- oder Microsoft-Konto bereits innerhalb von Dazr Identity nutzen. Ihre App braucht daneben also keine eigenen Google- und Microsoft-Buttons: ein Button statt drei.
Discovery und Endpunkte
Alles steht im Discovery-Dokument. Geben Sie Ihrer Bibliothek den Issuer an, den Rest findet sie selbst.
| Was | Adresse |
|---|---|
| Issuer | https://identity.dazr.eu |
| Discovery | https://identity.dazr.eu/.well-known/openid-configuration |
| Autorisierung | https://identity.dazr.eu/oauth/authorize |
| Token | https://identity.dazr.eu/oauth/token |
| Benutzerinfo | https://identity.dazr.eu/oauth/userinfo |
| Öffentliche Schlüssel (JWKS) | https://identity.dazr.eu/oauth/jwks |
| Widerruf (RFC 7009) | https://identity.dazr.eu/oauth/revoke |
| Introspektion (RFC 7662), nur für Webserver-Apps | https://identity.dazr.eu/oauth/introspect |
| Abmeldung (RP-initiated logout) | https://identity.dazr.eu/oauth/logout |
Eine App registrieren
- Apps gehören zu einer Organisation. Inhaber und Administratoren der Organisation registrieren sie unter Entwickler.
- Webserver-Apps (vertrauliche Clients) erhalten ein Client-Secret, das einmal angezeigt wird. Authentifizieren Sie sich am Token-Endpunkt mit HTTP Basic (
client_secret_basic) oder im Formular-Body (client_secret_post). - Single-Page- und mobile Apps (öffentliche Clients) erhalten kein Secret. Sie senden
client_idund verlassen sich auf PKCE. - Weiterleitungs-URIs müssen exakt übereinstimmen und mit
https://beginnen. Solange die App im Testmodus ist, funktionieren auchhttp://localhostundhttp://127.0.0.1auf jedem Port. - Eine Adresse der Datenschutzerklärung, eine Support-E-Mail und ein einzeiliger Zweck sind Pflicht: Die Nutzer sehen sie auf dem Zustimmungsbildschirm.
Integrationsanleitungen
Jeder Stack unten nutzt seine eigene Standardunterstützung für OpenID Connect. Sie brauchen drei Werte aus der Konsole: die Client-ID, das Client-Secret (nur bei Webserver-Apps) und die Weiterleitungs-URI, die Sie registriert haben. Den Rest liefert das Discovery-Dokument.
- Auth.js / NextAuth
- Next.js App Router
- WordPress
- Laravel
- Supabase
- Django
- Node.js (openid-client)
- Jede OpenID-Connect-Bibliothek
sub ist pairwise: gleich für jede App Ihrer Organisation, anders für jede andere Organisation. Er ändert sich für eine Person nie, eine E-Mail-Adresse dagegen schon. Speichern Sie sub als Schlüssel des Kontos und behandeln Sie email als Kontaktangabe.
Auth.js / NextAuth
Auth.js (NextAuth.js v5) akzeptiert ein eigenes OpenID-Connect-Provider-Objekt. Registrieren Sie eine Webserver-App, setzen Sie AUTH_SECRET, AUTH_DAZR_ID und AUTH_DAZR_SECRET und verwenden Sie diese Callback-URL als Weiterleitungs-URI: 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 funktioniert genauso, mit type: "oauth" und der Discovery-URL:
// 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
Ergänzen Sie mit der Datei auth.ts oben den Route Handler und einen Anmeldebutton, der eine Server Action ausführt.
// 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>
)
}
Gestalten Sie den Button wie unter Der Button gezeigt. In Callbacks ist die Dazr-sub der Wert account.providerAccountId.
WordPress
Verwenden Sie ein generisches OpenID-Connect-Client-Plugin, etwa OpenID Connect Generic Client. Registrieren Sie eine Webserver-App und füllen Sie die Plugin-Einstellungen mit den Werten unten aus. Das Plugin zeigt die zu registrierende Weiterleitungs-URI auf seiner Einstellungsseite; standardmäßig ist das https://example.com/wp-admin/admin-ajax.php?action=openid-connect-authorize.
| Einstellung | Wert |
|---|---|
| Client-ID | Ihre Client-ID |
| Client-Secret | Ihr Client-Secret |
| Scope | openid profile email |
| Login-Endpunkt (Autorisierung) | https://identity.dazr.eu/oauth/authorize |
| Token-Endpunkt | https://identity.dazr.eu/oauth/token |
| Userinfo-Endpunkt | https://identity.dazr.eu/oauth/userinfo |
| Endpunkt zum Beenden der Sitzung | https://identity.dazr.eu/oauth/logout |
| Identity Key (Identitätsschlüssel) | sub |
| PKCE | an (S256) |
Die Namen der Einstellungen unterscheiden sich je nach Plugin etwas. Hat ein Plugin keine PKCE-Option, wählen Sie ein anderes: Dazr Identity lehnt Anmeldungen ohne PKCE ab.
Laravel
Laravel Socialite hat keinen eingebauten generischen OpenID-Connect-Treiber, daher fügen Sie einen kleinen eigenen Treiber hinzu. Er schickt Menschen mit PKCE zu Dazr und liest den Nutzer am Userinfo-Endpunkt aus. Socialite liest das Discovery-Dokument nicht, deshalb stehen die Endpunkte ausgeschrieben da. Registrieren Sie eine Webserver-App mit der Weiterleitungs-URI 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 hat keinen generischen OpenID-Connect-Provider, den Sie auf einen beliebigen Issuer richten können: Die Anmeldeanbieter und die Third-Party-Auth-Integrationen sind feste Listen. Sie können Dazr Identity daher derzeit nicht im Supabase-Dashboard hinzufügen. Falls Supabase generische OpenID-Connect-Unterstützung ergänzt, verwenden Sie die Werte aus der Checkliste unten.
Die Alternative: Melden Sie Menschen auf Ihrem eigenen Server mit Dazr Identity an (mit einer der Anleitungen auf dieser Seite), speichern Sie die Dazr-sub in Ihrer Nutzertabelle und sprechen Sie von diesem Server aus mit dem Service-Role-Key mit Supabase, wobei Ihr eigener Code die Zugriffe prüft. Senden Sie den Service-Role-Key nie an einen Browser.
Django
Verwenden Sie mozilla-django-oidc. Registrieren Sie eine Webserver-App mit der Weiterleitungs-URI https://app.example.eu/oidc/callback/. Die Bibliothek liest das Discovery-Dokument nicht, deshalb stehen die Endpunkte ausgeschrieben da.
# 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>
Standardmäßig ordnet das Backend Nutzer über die E-Mail zu. Um Konten über sub zu verknüpfen, leiten Sie von OIDCAuthenticationBackend ab und überschreiben filter_users_by_claims und create_user. Verwenden Sie eine aktuelle Version: Ältere Versionen können ES256-Signaturen nicht prüfen.
Node.js (openid-client)
openid-client (Version 6) liest das Discovery-Dokument und prüft PKCE, State, Nonce und das ID-Token für Sie.
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 };
}
Jede OpenID-Connect-Bibliothek
Ist Ihr Stack nicht aufgeführt, funktioniert jeder OpenID-Connect-Client. Prüfen Sie diese Einstellungen:
- Issuer
https://identity.dazr.eu, Discovery-URLhttps://identity.dazr.eu/.well-known/openid-configuration. - Response Type
code(Authorization Code Flow). Kein Implicit oder Hybrid Flow. - PKCE ist Pflicht, mit
code_challenge_method=S256. - Scopes:
openidund nur das, was Sie brauchen, ausprofile,email,address,organisationsundoffline_access. Ihre App muss für jeden angefragten Scope registriert sein. - Weiterleitungs-URI: genau wie in der Konsole registriert, einschließlich Pfad und gegebenenfalls Query-String.
- Client-Authentifizierung:
client_secret_basicoderclient_secret_postfür Webserver-Apps,nonefür Single-Page- und mobile Apps. - Signatur des ID-Tokens: ES256. Manche Bibliotheken setzen RS256 voraus: Stellen Sie den Algorithmus auf ES256.
- Verwenden Sie
subals Schlüssel des Kontos. Sie ist pairwise, pro Organisation. - Mit
offline_accessspeichern Sie nach jedem Refresh das neue Refresh-Token: Sie rotieren.
Der Ablauf
- Erzeugen Sie einen zufälligen
code_verifier(43 bis 128 Zeichen) und die zugehörigecode_challenge= base64url(SHA-256(verifier)). Erzeugen Sie einen zufälligenstateundnonce. Speichern Sie alle drei in der Sitzung des Nutzers. - Leiten Sie zum Autorisierungsendpunkt weiter mit
response_type=code,client_id,redirect_uri,scope(immer mitopenid),state,nonce,code_challengeundcode_challenge_method=S256. - Die Person meldet sich bei Bedarf an und sieht den Zustimmungsbildschirm mit den echten Daten. Stimmt sie zu, kommt sie mit
code,stateundisszu Ihrer Weiterleitungs-URI zurück. Prüfen Sie, dassstateübereinstimmt undissgleichhttps://identity.dazr.euist. - Senden Sie auf Ihrem Server einen POST an den Token-Endpunkt mit
grant_type=authorization_code,code, derselbenredirect_uriund demcode_verifier. - Verifizieren Sie das ID-Token: ES256-Signatur mit einem Schlüssel aus dem JWKS (passend zur
kid),iss,aud= Ihre Client-ID,expund Ihrenonce. Nutzen Siesubals Kontoschlüssel.
Der Parameter prompt akzeptiert none (sofortige Antwort mit login_required oder consent_required, wenn die Person etwas tun müsste), login (die Person erneut anmelden lassen) und consent (den Zustimmungsbildschirm zeigen, auch wenn schon zugestimmt wurde). max_age wird unterstützt. Gespeicherte Zustimmung: Hat die Person dieselben Scopes schon genehmigt, geht es direkt zurück zu Ihrer App. Fragen Sie später nach mehr, zeigt der Zustimmungsbildschirm nur das Neue.
Scopes und Claims
Fordern Sie nur an, was Sie brauchen. Außerhalb dieser Tabelle gibt es nichts: keine Kontakte, keine Dateien, keine Passwörter.
| Scope | Claims |
|---|---|
openid (Pflicht) | sub: eine zufällige ID für die Person, gleich für jede App Ihrer Organisation und anders für jede andere Organisation |
profile | name (falls festgelegt) und locale |
email | email und email_verified (immer true) |
address | address (formatted, street_address, locality, region, postal_code, country), nur wenn die Person eine Adresse gespeichert hat |
organisations | organisations: die Organisationen, die die Person auf dem Zustimmungsbildschirm ankreuzt, jeweils mit id, name, country, register_number, vat, vat_verified (nur true, wenn der EU-Dienst VIES die USt-IdNr. bestätigt hat), verified, verification (siehe Verifizierte Organisationen) und role |
offline_access | keine Claims; Sie erhalten zusätzlich ein Refresh-Token |
Claims stehen im ID-Token für die Scopes, die die Person genehmigt hat. Der Userinfo-Endpunkt liefert dieselben Angaben mit den aktuellen Werten.
Verifizierte Organisationen
Dazr verifiziert eine Organisation, wenn ihr Geschäftsführer oder eine andere zeichnungsberechtigte Person eine kurze Erklärung mit einer qualifizierten elektronischen Signatur (QES) unterschreibt. Das geht sofort und funktioniert in jedem EU-Land. Ohne qualifizierte Signatur kann der Vertreter stattdessen einen Handelsregisterauszug und einen Ausweis senden; Dazr prüft diese von Hand. Jede Organisation im Claim organisations enthält ihre aktuelle Verifizierung:
| verification.status | Bedeutung |
|---|---|
unverified | Nicht verifiziert, oder eine Verifizierung ist fehlgeschlagen, abgelaufen oder wurde widerrufen (zum Beispiel nach einer Änderung des Firmennamens oder der Registernummer). |
pending | Die Verifizierung läuft: Der Vertreter wurde um seine Unterschrift gebeten, oder Dazr prüft Dokumente. |
verified | Verifiziert. method ist qes, qes_org (das Zertifikat selbst nennt die Organisation, per USt-IdNr. oder Registernummer), documents oder extract, und verified_at ist eine Unix-Zeit. |
Das Boolean verified bleibt aus Kompatibilitätsgründen und entspricht verification.status === 'verified'. Jede Organisation hat außerdem eine id, dieselbe wie in den 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"
}]
Verifizierte Organisation verlangen
Setzen Sie in der Konsole Verifizierte Organisation verlangen auf Verifizierung gestartet oder Verifiziert, oder verlangen Sie es pro Anfrage mit acr_values=urn:dazr:org:verification-started oder acr_values=urn:dazr:org:verified (die strengere Vorgabe gilt). Ihre App muss außerdem den Scope organisations anfragen.
Wer keine passende Organisation hat, durchläuft das in derselben Anmeldung: Name, Organisation (mit in VIES geprüfter USt-IdNr.), dann die Verifizierung. Die Person kann sofort unterschreiben, sich die Erklärung per E-Mail schicken lassen oder eine andere Person nennen, die unterschreibt. Danach kreuzt sie die Organisation auf dem Zustimmungsbildschirm an (nur passende Organisationen sind auswählbar) und kehrt zu Ihrer Weiterleitungs-URI zurück.
Muss noch jemand anderes unterschreiben, kommt die Person mit Status pending zurück, auch wenn Sie Verifiziert verlangt haben: Sie erhalten einen Code, der Claim sagt pending, und das acr des ID-Tokens ist urn:dazr:org:verification-started statt urn:dazr:org:verified. Entscheiden Sie immer anhand von verification.status, nie anhand einer erfolgreichen Anmeldung. Mit prompt=none erhalten Sie interaction_required, wenn die Vorgabe nicht erfüllt ist.
Änderungen der Einstellung gelten ab der nächsten Anmeldung. Bereits angemeldete Personen werden nicht abgemeldet: Refresh-Antworten, der Userinfo-Endpunkt und Webhooks enthalten immer den aktuellen Status, nutzen Sie diese also für bestehende Sitzungen.
Webhooks
Fügen Sie in der Konsole eine Webhook-URL (https) hinzu. Das Signatur-Secret sehen Sie einmal; Sie können es erneuern. Dazr sendet organisation.verification.updated, wenn eine Organisation, die einer Ihrer Nutzer mit Ihrer App geteilt hat, pending, verified, failed oder unverified wird. Apps, die eine Organisation nie per Zustimmung erhalten haben, erfahren nie davon.
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 ist pending, verified, failed oder unverified. subjects sind die sub-Werte, in Ihrer App, der Personen, die diese Organisation mit ihr geteilt haben. Prüfen Sie die Signatur, bevor Sie dem Inhalt vertrauen:
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]));
}
Antworten Sie innerhalb von 8 Sekunden mit einem 2xx. Sonst versucht Dazr es nach etwa 5 Minuten, 30 Minuten, 2, 6, 12 und 24 Stunden erneut und markiert die Zustellung dann als fehlgeschlagen. Jeder Versuch hat dieselbe Dazr-Delivery-ID, ignorieren Sie also Duplikate. Die Konsole listet die letzten Zustellungen, kann eine erneut senden und ein Testereignis senden (webhook.test). Regelmäßiges Abfragen des Userinfo-Endpunkts funktioniert ebenfalls.
Tokens und Laufzeiten
| Token | Laufzeit und Regeln |
|---|---|
| Autorisierungscode | 60 Sekunden, einmalig, gebunden an Ihren Client, die Weiterleitungs-URI und die PKCE-Challenge. Wird ein Code zweimal verwendet, werden die damit ausgestellten Tokens widerrufen. |
| Access-Token | 10 Minuten. Ein signiertes JWT (ES256, typ at+jwt) mit aud = Ihre Client-ID. Senden Sie es als Authorization: Bearer. |
| ID-Token | 10 Minuten. ES256, mit iss, sub, aud, exp, iat, auth_time, nonce und amr, soweit bekannt. |
| Refresh-Token | Nur mit offline_access. Wird bei jeder Nutzung erneuert: Speichern Sie immer das neue. Wird ein altes Refresh-Token erneut gesendet, wird die gesamte Anmeldung widerrufen. Läuft nach 30 Tagen ohne Nutzung und spätestens nach 180 Tagen ab. |
Signaturschlüssel werden gewechselt. Wählen Sie den Schlüssel immer anhand der kid aus dem JWKS und laden Sie das JWKS neu, wenn Sie eine unbekannte kid sehen.
Fehler
Solange Client-ID und Weiterleitungs-URI gültig sind, kommen Fehler an Ihre Weiterleitungs-URI zurück als error, error_description, state und iss: zum Beispiel invalid_request (etwa fehlendes oder plain PKCE), invalid_scope, unsupported_response_type, access_denied (die Person hat abgebrochen, oder die App ist im Testmodus und die Person ist kein Mitglied), login_required, consent_required und interaction_required (mit prompt=none, wenn eine verlangte verifizierte Organisation fehlt). Bei einem unbekannten Client oder einer nicht registrierten Weiterleitungs-URI zeigt Dazr eine Fehlerseite und leitet nie weiter. Der Token-Endpunkt antwortet mit JSON-Fehlern wie invalid_client, invalid_grant und unsupported_grant_type.
Abmeldung
Um jemanden abzumelden, schicken Sie die Person zum Abmeldeendpunkt mit id_token_hint (oder client_id), einer optionalen, in den App-Einstellungen registrierten post_logout_redirect_uri und state. Dazr fragt, ob sie sich auf diesem Gerät auch von Dazr Identity abmelden möchte, und schickt sie dann zurück. Widerrufen Sie nicht mehr benötigte Refresh-Tokens am Widerrufsendpunkt.
Testen und live gehen
Eine neue App ist im Testmodus: Nur Mitglieder Ihrer Organisation können sich anmelden, und der Zustimmungsbildschirm weist darauf hin. Um live zu gehen, lassen Sie Ihre Organisation in Dazr Identity verifizieren, fügen eine https://-Weiterleitungs-URI hinzu und beantragen in der Konsole eine Prüfung. Ändern Sie Name, Zweck, Datenschutzerklärung oder Daten einer Live-App, ist eine neue Prüfung nötig.
Der Button
Verwenden Sie den Text „Sign in with Dazr Identity“ und das Dazr-Logo wie unten. Sie dürfen die Größe ändern, nicht das Logo, die Farben oder den Text. Verlinken Sie ihn auf Ihre eigene Route, die den Ablauf startet.
<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>
Ein minimales Beispiel in Node.js
Node 18 oder neuer, ohne Abhängigkeiten. Eine Webserver-App mit Client-Secret; bei einem öffentlichen Client entfällt der Authorization-Header und Sie senden client_id im Body.
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;
}
Limits
Der Autorisierungs- und der Token-Endpunkt sind begrenzt. Erhalten Sie HTTP 429, warten Sie und versuchen Sie es erneut; wiederholen Sie es nicht in einer engen Schleife.
Ihre Pflichten
Ihre Organisation ist eigenständiger Verantwortlicher für die Daten, die sie erhält. Die Entwicklerbedingungen für Dazr Identity legen fest, was Sie damit tun dürfen, wie Sie sie schützen und wie Sie Datenpannen melden. Fragen: hello@dazr.eu.