Sign in with Dazr Identity: dokumentacja dla deweloperów
Standardowy OpenID Connect 1.0 z przepływem authorization code i PKCE. Bez SDK: działa każda certyfikowana biblioteka OpenID Connect, a także własny kod.
Użytkownicy mogą już korzystać z konta Google lub Microsoft w Dazr Identity, więc Twoja aplikacja nie potrzebuje obok osobnych przycisków Google i Microsoft: jeden przycisk zamiast trzech.
Discovery i endpointy
Wszystko jest opisane w dokumencie discovery. Wskaż bibliotece wystawcę, a resztę znajdzie sama.
| Co | Adres |
|---|---|
| Wystawca | https://identity.dazr.eu |
| Discovery | https://identity.dazr.eu/.well-known/openid-configuration |
| Autoryzacja | https://identity.dazr.eu/oauth/authorize |
| Token | https://identity.dazr.eu/oauth/token |
| Informacje o użytkowniku | https://identity.dazr.eu/oauth/userinfo |
| Klucze publiczne (JWKS) | https://identity.dazr.eu/oauth/jwks |
| Unieważnianie (RFC 7009) | https://identity.dazr.eu/oauth/revoke |
| Introspekcja (RFC 7662), tylko aplikacje serwerowe | https://identity.dazr.eu/oauth/introspect |
| Wylogowanie (RP-initiated logout) | https://identity.dazr.eu/oauth/logout |
Rejestracja aplikacji
- Aplikacje należą do organizacji. Właściciele i administratorzy organizacji rejestrują je w sekcji Deweloperzy.
- Aplikacje serwerowe (klienci poufni) otrzymują sekret klienta, wyświetlany tylko raz. Uwierzytelniaj się w endpoincie tokenów przez HTTP Basic (
client_secret_basic) lub w treści formularza (client_secret_post). - Aplikacje jednostronicowe i mobilne (klienci publiczni) nie dostają sekretu. Wysyłają
client_idi polegają na PKCE. - Adresy URI przekierowania muszą zgadzać się dokładnie i zaczynać od
https://. Dopóki aplikacja jest w trybie testowym, działają teżhttp://localhostihttp://127.0.0.1na dowolnym porcie. - Wymagane są adres polityki prywatności, e-mail wsparcia i jednozdaniowy cel: ludzie widzą je na ekranie zgody.
Instrukcje integracji
Każdy stack poniżej korzysta z własnej standardowej obsługi OpenID Connect. Potrzebujesz trzech wartości z konsoli: identyfikatora klienta, sekretu klienta (tylko aplikacje serwerowe) i zarejestrowanego URI przekierowania. Resztę zawiera dokument discovery.
- Auth.js / NextAuth
- Next.js App Router
- WordPress
- Laravel
- Supabase
- Django
- Node.js (openid-client)
- Dowolna biblioteka OpenID Connect
sub jest pairwise: taki sam dla każdej aplikacji Twojej organizacji i inny dla każdej innej organizacji. Dla danej osoby nigdy się nie zmienia, a adres e-mail może. Zapisuj sub jako klucz konta, a email traktuj jako dane kontaktowe.
Auth.js / NextAuth
Auth.js (NextAuth.js v5) przyjmuje własny obiekt dostawcy OpenID Connect. Zarejestruj aplikację serwerową, ustaw AUTH_SECRET, AUTH_DAZR_ID i AUTH_DAZR_SECRET i użyj tego adresu callback jako URI przekierowania: 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 działa tak samo, z type: "oauth" i adresem 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
Mając plik auth.ts powyżej, dodaj route handler i przycisk logowania, który uruchamia 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>
)
}
Nadaj przyciskowi styl pokazany w sekcji Przycisk. W callbackach sub z Dazr to account.providerAccountId.
WordPress
Użyj ogólnej wtyczki klienta OpenID Connect, np. OpenID Connect Generic Client. Zarejestruj aplikację serwerową i wypełnij ustawienia wtyczki wartościami poniżej. Wtyczka pokazuje URI przekierowania do zarejestrowania na swojej stronie ustawień; domyślnie jest to https://example.com/wp-admin/admin-ajax.php?action=openid-connect-authorize.
| Ustawienie | Wartość |
|---|---|
| Identyfikator klienta | Twój identyfikator klienta |
| Sekret klienta | Twój sekret klienta |
| Scope | openid profile email |
| Endpoint logowania (autoryzacji) | https://identity.dazr.eu/oauth/authorize |
| Endpoint tokenów | https://identity.dazr.eu/oauth/token |
| Endpoint userinfo | https://identity.dazr.eu/oauth/userinfo |
| Endpoint zakończenia sesji | https://identity.dazr.eu/oauth/logout |
| Identity key (klucz tożsamości) | sub |
| PKCE | włączone (S256) |
Nazwy ustawień różnią się nieco między wtyczkami. Jeśli wtyczka nie ma opcji PKCE, wybierz inną: Dazr Identity odrzuca logowania bez PKCE.
Laravel
Laravel Socialite nie ma wbudowanego ogólnego sterownika OpenID Connect, więc dodaj mały własny sterownik. Kieruje on ludzi do Dazr z PKCE i odczytuje użytkownika z endpointu userinfo. Socialite nie czyta dokumentu discovery, dlatego endpointy są wpisane wprost. Zarejestruj aplikację serwerową z URI przekierowania 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 nie ma ogólnego dostawcy OpenID Connect, którego można skierować na dowolnego wystawcę: dostawcy logowania i integracje uwierzytelniania zewnętrznego to stałe listy. Dlatego dziś nie dodasz Dazr Identity w panelu Supabase. Jeśli Supabase doda ogólną obsługę OpenID Connect, użyj wartości z listy poniżej.
Alternatywa: loguj ludzi przez Dazr Identity na własnym serwerze (według jednej z instrukcji na tej stronie), zapisz sub z Dazr w tabeli użytkowników i komunikuj się z Supabase z tego serwera za pomocą klucza service role, sprawdzając dostęp we własnym kodzie. Nigdy nie wysyłaj klucza service role do przeglądarki.
Django
Użyj mozilla-django-oidc. Zarejestruj aplikację serwerową z URI przekierowania https://app.example.eu/oidc/callback/. Biblioteka nie czyta dokumentu discovery, dlatego endpointy są wpisane wprost.
# 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>
Domyślnie backend dopasowuje użytkowników po adresie e-mail. Aby łączyć konta przez sub, utwórz podklasę OIDCAuthenticationBackend i nadpisz filter_users_by_claims oraz create_user. Używaj aktualnej wersji: starsze wersje nie weryfikują podpisów ES256.
Node.js (openid-client)
openid-client (wersja 6) czyta dokument discovery i sprawdza za Ciebie PKCE, state, nonce oraz token ID.
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 };
}
Dowolna biblioteka OpenID Connect
Jeśli Twojego stacku nie ma na liście, zadziała dowolny klient OpenID Connect. Sprawdź te ustawienia:
- Wystawca
https://identity.dazr.eu, adres discoveryhttps://identity.dazr.eu/.well-known/openid-configuration. - Typ odpowiedzi
code(przepływ authorization code). Bez przepływu implicit ani hybrid. - PKCE jest wymagane, z
code_challenge_method=S256. - Scope’y:
openidplus tylko to, czego potrzebujesz, spośródprofile,email,address,organisationsioffline_access. Aplikacja musi być zarejestrowana dla każdego scope’u, o który prosi. - URI przekierowania: dokładnie taki, jak zarejestrowany w konsoli, łącznie ze ścieżką i ewentualnym query stringiem.
- Uwierzytelnianie klienta:
client_secret_basiclubclient_secret_postdla aplikacji serwerowych,nonedla aplikacji jednostronicowych i mobilnych. - Podpis tokenu ID: ES256. Niektóre biblioteki zakładają RS256: ustaw algorytm na ES256.
- Używaj
subjako klucza konta. Jest pairwise, osobny dla każdej organizacji. - Przy
offline_accesszapisuj nowy refresh token po każdym odświeżeniu: tokeny rotują.
Przepływ
- Utwórz losowy
code_verifier(od 43 do 128 znaków) i jegocode_challenge= base64url(SHA-256(verifier)). Utwórz losowestateinonce. Zachowaj wszystkie trzy w sesji użytkownika. - Przekieruj do endpointu autoryzacji z
response_type=code,client_id,redirect_uri,scope(zawsze zopenid),state,nonce,code_challengeicode_challenge_method=S256. - Osoba w razie potrzeby się loguje i widzi ekran zgody z prawdziwymi danymi. Gdy wyrazi zgodę, wraca na Twój URI przekierowania z
code,stateiiss. Sprawdź, czystatesię zgadza, aisstohttps://identity.dazr.eu. - Na swoim serwerze wyślij POST do endpointu tokenów z
grant_type=authorization_code,code, tym samymredirect_uriicode_verifier. - Zweryfikuj ID token: podpis ES256 kluczem z JWKS (według
kid),iss,aud= Twój identyfikator klienta,expi Twójnonce. Używajsubjako klucza konta.
Parametr prompt przyjmuje none (natychmiastowa odpowiedź login_required lub consent_required, jeśli osoba musiałaby coś zrobić), login (poproś o ponowne zalogowanie) i consent (pokaż ekran zgody, nawet jeśli wcześniej ją wyrażono). Obsługiwany jest max_age. Zapamiętana zgoda: jeśli osoba wcześniej zatwierdziła te same scope’y, od razu wraca do Twojej aplikacji. Jeśli później poprosisz o więcej, ekran zgody pokaże tylko nowe pozycje.
Scope’y i claimy
Proś tylko o to, czego potrzebujesz. Poza tą tabelą nic nie istnieje: żadnych kontaktów, plików ani haseł.
| Scope | Claimy |
|---|---|
openid (wymagany) | sub: losowy identyfikator osoby, taki sam dla każdej aplikacji Twojej organizacji i inny dla każdej innej organizacji |
profile | name (jeśli ustawione) i locale |
email | email i email_verified (zawsze true) |
address | address (formatted, street_address, locality, region, postal_code, country), tylko jeśli osoba zapisała adres |
organisations | organisations: organizacje zaznaczone przez osobę na ekranie zgody, każda z id, name, country, register_number, vat, vat_verified (true tylko wtedy, gdy unijna usługa VIES potwierdziła numer VAT), verified, verification (zob. Zweryfikowane organizacje) i role |
offline_access | brak claimów; dodatkowo otrzymujesz refresh token |
Claimy trafiają do ID tokenu dla scope’ów zatwierdzonych przez osobę. Endpoint informacji o użytkowniku zwraca ten sam zestaw z aktualnymi wartościami.
Zweryfikowane organizacje
Dazr weryfikuje organizację, gdy członek zarządu lub inna osoba upoważniona do podpisu podpisze krótkie oświadczenie kwalifikowanym podpisem elektronicznym (QES). To działa od razu, w każdym kraju UE. Bez podpisu kwalifikowanego reprezentant może zamiast tego przesłać odpis z rejestru i dokument tożsamości; Dazr sprawdza je ręcznie. Każda organizacja w claimie organisations zawiera swoją aktualną weryfikację:
| verification.status | Znaczenie |
|---|---|
unverified | Niezweryfikowana albo weryfikacja się nie powiodła, wygasła lub została cofnięta (na przykład po zmianie nazwy lub numeru rejestrowego). |
pending | Weryfikacja trwa: reprezentanta poproszono o podpis albo Dazr sprawdza dokumenty. |
verified | Zweryfikowana. method to qes, qes_org (sam certyfikat wskazuje organizację, przez numer VAT lub rejestrowy), documents lub extract, a verified_at to czas uniksowy. |
Wartość logiczna verified zostaje dla zgodności i równa się verification.status === 'verified'. Każda organizacja ma też id, to samo co w webhookach.
"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"
}]
Wymaganie zweryfikowanej organizacji
W konsoli ustaw Wymagaj zweryfikowanej organizacji na Weryfikacja rozpoczęta lub Zweryfikowana albo żądaj tego w pojedynczym żądaniu przez acr_values=urn:dazr:org:verification-started lub acr_values=urn:dazr:org:verified (obowiązuje surowsza z dwóch opcji). Twoja aplikacja musi też prosić o scope organisations.
Osoba bez odpowiedniej organizacji przechodzi przez to w tym samym logowaniu: imię i nazwisko, organizacja (z numerem VAT sprawdzonym w VIES), a potem weryfikacja. Może podpisać od razu, wysłać sobie oświadczenie e-mailem albo wskazać inną osobę, która podpisze. Następnie zaznacza organizację na ekranie zgody (można zaznaczyć tylko odpowiednie organizacje) i wraca na Twój URI przekierowania.
Jeśli ktoś inny musi jeszcze podpisać, osoba wraca ze statusem pending, także gdy żądasz Zweryfikowana: otrzymujesz kod, claim mówi pending, a acr tokenu ID to urn:dazr:org:verification-started zamiast urn:dazr:org:verified. Zawsze decyduj na podstawie verification.status, nigdy na podstawie udanego logowania. Z prompt=none otrzymasz interaction_required, gdy wymaganie nie jest spełnione.
Zmiany ustawienia obowiązują od następnego logowania. Zalogowani użytkownicy nie są wylogowywani: odpowiedzi refresh, endpoint userinfo i webhooki zawsze zawierają aktualny status, więc używaj ich do reagowania w istniejących sesjach.
Webhooki
Dodaj w konsoli adres URL webhooka (https). Sekret podpisu widzisz raz; możesz go zmienić. Dazr wysyła organisation.verification.updated, gdy organizacja udostępniona Twojej aplikacji przez jednego z użytkowników zmieni status na pending, verified, failed lub unverified. Aplikacje, które nigdy nie otrzymały organizacji przez zgodę, nigdy się o niej nie dowiedzą.
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 to pending, verified, failed lub unverified. subjects to wartości sub, w Twojej aplikacji, osób, które jej udostępniły tę organizację. Sprawdź podpis, zanim zaufasz treści:
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]));
}
Odpowiedz kodem 2xx w ciągu 8 sekund. W przeciwnym razie Dazr ponawia próbę po około 5 minutach, 30 minutach, 2, 6, 12 i 24 godzinach, a potem oznacza dostarczenie jako nieudane. Każda próba ma ten sam identyfikator Dazr-Delivery, więc ignoruj duplikaty. Konsola pokazuje ostatnie dostarczenia, może wysłać jedno ponownie i wysłać zdarzenie testowe (webhook.test). Odpytywanie endpointu userinfo też działa.
Tokeny i ich ważność
| Token | Ważność i zasady |
|---|---|
| Kod autoryzacji | 60 sekund, jednorazowy, powiązany z Twoim klientem, URI przekierowania i challenge’em PKCE. Dwukrotne użycie kodu unieważnia wydane nim tokeny. |
| Access token | 10 minut. Podpisany JWT (ES256, typ at+jwt) z aud = Twój identyfikator klienta. Wysyłaj go jako Authorization: Bearer. |
| ID token | 10 minut. ES256, z iss, sub, aud, exp, iat, auth_time, nonce i amr, jeśli jest znane. |
| Refresh token | Tylko z offline_access. Zmienia się przy każdym użyciu: zawsze zapisuj nowy. Ponowne wysłanie starego refresh tokenu unieważnia całe logowanie. Wygasa po 30 dniach nieużywania i najpóźniej po 180 dniach. |
Klucze podpisu są wymieniane. Zawsze wybieraj klucz według kid z JWKS i pobierz JWKS ponownie, gdy zobaczysz nieznany kid.
Błędy
Dopóki identyfikator klienta i URI przekierowania są prawidłowe, błędy wracają na Twój URI przekierowania jako error, error_description, state i iss: na przykład invalid_request (np. brak PKCE lub plain), invalid_scope, unsupported_response_type, access_denied (osoba anulowała albo aplikacja jest w trybie testowym, a osoba nie jest członkiem), login_required, consent_required i interaction_required (z prompt=none, gdy brakuje wymaganej zweryfikowanej organizacji). Przy nieznanym kliencie lub niezarejestrowanym URI przekierowania Dazr pokazuje stronę błędu i nigdy nie przekierowuje. Endpoint tokenów odpowiada błędami JSON, takimi jak invalid_client, invalid_grant i unsupported_grant_type.
Wylogowanie
Aby kogoś wylogować, skieruj tę osobę do endpointu wylogowania z id_token_hint (lub client_id), opcjonalnym post_logout_redirect_uri zarejestrowanym w ustawieniach aplikacji i state. Dazr zapyta, czy chce też wylogować się z Dazr Identity na tym urządzeniu, a potem odeśle ją z powrotem. Niepotrzebne refresh tokeny unieważniaj w endpoincie unieważniania.
Testy i uruchomienie
Nowa aplikacja jest w trybie testowym: logować się mogą tylko członkowie Twojej organizacji, a ekran zgody o tym informuje. Aby ją uruchomić, zweryfikuj organizację w Dazr Identity, dodaj URI przekierowania https:// i poproś w konsoli o weryfikację. Zmiana nazwy, celu, polityki prywatności lub danych działającej aplikacji wymaga nowej weryfikacji.
Przycisk
Używaj tekstu „Sign in with Dazr Identity” i logo Dazr jak poniżej. Możesz zmieniać rozmiar, ale nie logo, kolory ani tekst. Podlinkuj go do własnej ścieżki, która rozpoczyna przepływ.
<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>
Minimalny przykład w Node.js
Node 18 lub nowszy, bez zależności. Aplikacja serwerowa z sekretem klienta; w przypadku klienta publicznego usuń nagłówek Authorization i wyślij client_id w treści.
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;
}
Limity
Endpointy autoryzacji i tokenów mają limity zapytań. Jeśli dostaniesz HTTP 429, odczekaj i spróbuj ponownie; nie ponawiaj w ciasnej pętli.
Twoje obowiązki
Twoja organizacja jest niezależnym administratorem otrzymanych danych. Warunki dla deweloperów Dazr Identity określają, co możesz z nimi robić, jak je chronić i jak zgłaszać naruszenia. Pytania: hello@dazr.eu.