Přihlášení přes Dazr Identity: dokumentace pro vývojáře

Lidé už mohou uvnitř Dazr Identity používat svůj účet Google nebo Microsoft, takže vaše aplikace nepotřebuje vedle něj samostatná tlačítka Google a Microsoft: jedno tlačítko místo tří.

Discovery a koncové body

Vše je popsáno v dokumentu discovery. Nasměrujte svou knihovnu na vydavatele a zbytek si najde sama.

CoAdresa
Vydavatel (issuer)https://identity.dazr.eu
Discoveryhttps://identity.dazr.eu/.well-known/openid-configuration
Autorizacehttps://identity.dazr.eu/oauth/authorize
Tokenhttps://identity.dazr.eu/oauth/token
Informace o uživatelihttps://identity.dazr.eu/oauth/userinfo
Veřejné klíče (JWKS)https://identity.dazr.eu/oauth/jwks
Zneplatnění (RFC 7009)https://identity.dazr.eu/oauth/revoke
Introspekce (RFC 7662), jen webové serverové aplikacehttps://identity.dazr.eu/oauth/introspect
Odhlášení (odhlášení iniciované RP)https://identity.dazr.eu/oauth/logout
Zprávy o ověření, jen webové serverové aplikacehttps://identity.dazr.eu/oauth/verification-report

Registrace aplikace

Aplikace ve vývojářské konzoli Dazr Identity: client ID, discovery URL, URI pro přesměrování, rozsahy a kroky k propojení

Návody k integraci

Každá níže uvedená technologie používá vlastní standardní podporu OpenID Connect. Z konzole potřebujete tři hodnoty: client ID, tajemství klienta (jen webové serverové aplikace) a URI pro přesměrování, které jste zaregistrovali. Zbytek pochází z dokumentu discovery.

Auth.js / NextAuth

Auth.js (NextAuth.js v5) přijímá vlastní objekt poskytovatele OpenID Connect. Zaregistrujte webovou serverovou aplikaci, nastavte AUTH_SECRET, AUTH_DAZR_ID a AUTH_DAZR_SECRET a jako URI pro přesměrování použijte tuto URL zpětného volání: 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 používá stejný princip s type: "oauth" a 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

Se souborem auth.ts výše přidejte obsluhu trasy a přihlašovací tlačítko, které spustí serverovou akci.

// 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>
  )
}

Tlačítko nastylujte podle části Tlačítko. V callbackech je Dazr sub hodnotou account.providerAccountId.

WordPress

Použijte obecný klientský plugin OpenID Connect, například OpenID Connect Generic Client. Zaregistrujte webovou serverovou aplikaci a vyplňte nastavení pluginu hodnotami níže. Plugin na své stránce nastavení zobrazuje URI pro přesměrování k registraci; výchozí je https://example.com/wp-admin/admin-ajax.php?action=openid-connect-authorize.

NastaveníHodnota
Client IDvaše client ID
Tajemství klientavaše tajemství klienta
Scopeopenid profile email
Koncový bod přihlášení (autorizace)https://identity.dazr.eu/oauth/authorize
Tokenový koncový bodhttps://identity.dazr.eu/oauth/token
Koncový bod informací o uživatelihttps://identity.dazr.eu/oauth/userinfo
Koncový bod ukončení relacehttps://identity.dazr.eu/oauth/logout
Klíč identitysub
PKCEzapnuto (S256)

Názvy nastavení se mezi pluginy trochu liší. Pokud plugin nemá volbu PKCE, zvolte jiný: Dazr Identity odmítá přihlášení bez PKCE.

Laravel

Laravel Socialite nemá vestavěný obecný ovladač OpenID Connect, proto přidejte malý vlastní ovladač. Posílá lidi do Dazr s PKCE a čte uživatele z koncového bodu informací o uživateli. Socialite nečte dokument discovery, proto jsou koncové body vypsány. Zaregistrujte webovou serverovou aplikaci s URI pro přesměrování 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 nemá obecného poskytovatele OpenID Connect, kterého by bylo možné nasměrovat na libovolného vydavatele: jeho poskytovatelé přihlášení a integrace ověřování třetích stran jsou pevné seznamy. Dazr Identity proto dnes v řídicím panelu Supabase přidat nelze. Pokud Supabase přidá obecnou podporu OpenID Connect, použijte hodnoty z kontrolního seznamu níže.

Alternativa: přihlašujte lidi přes Dazr Identity na vlastním serveru (podle některého z návodů na této stránce), ukládejte Dazr sub do své tabulky uživatelů a komunikujte se Supabase z tohoto serveru pomocí klíče service role, s kontrolou přístupu ve vlastním kódu. Klíč service role nikdy neposílejte do prohlížeče.

Django

Použijte mozilla-django-oidc. Zaregistrujte webovou serverovou aplikaci s URI pro přesměrování https://app.example.eu/oidc/callback/. Knihovna nečte dokument discovery, proto jsou koncové body vypsány.

# 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>

Ve výchozím stavu backend páruje uživatele podle e-mailu. Chcete-li klíčovat účty podle sub, vytvořte podtřídu OIDCAuthenticationBackend a přepište filter_users_by_claims a create_user. Používejte aktuální verzi: starší verze neumí ověřovat podpisy ES256.

Node.js (openid-client)

openid-client (verze 6) čte dokument discovery a za vás kontroluje PKCE, state, nonce a ID token.

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 };
}

Jakákoli knihovna OpenID Connect

Pokud vaše technologie není uvedena, funguje jakýkoli klient OpenID Connect. Zkontrolujte tato nastavení:

Tok

  1. Vytvořte náhodný code_verifier (43 až 128 znaků) a jeho code_challenge = base64url(SHA-256(verifier)). Vytvořte náhodné state a nonce. Všechny tři uchovávejte v relaci uživatele.
  2. Přesměrujte na autorizační koncový bod s response_type=code, client_id, redirect_uri, scope (vždy včetně openid), state, nonce, code_challenge a code_challenge_method=S256.
  3. Osoba se v případě potřeby přihlásí a uvidí obrazovku souhlasu se skutečnými údaji. Když souhlas udělí, vrátí se na vaše URI pro přesměrování s code, state a iss. Ověřte, že state se shoduje a iss je https://identity.dazr.eu.
  4. Na svém serveru pošlete POST na tokenový koncový bod s grant_type=authorization_code, code, stejným redirect_uri a code_verifier.
  5. Ověřte ID token: podpis ES256 klíčem z JWKS (shoda kid), iss, aud = vaše client ID, exp a váš nonce. Jako klíč účtu používejte sub.
Obrazovka souhlasu Dazr Identity pro aplikaci Ledgerline: uvádí jméno, e-mailovou adresu a ověřenou organizaci, kterou se uživatel rozhodl sdílet

Parametr prompt přijímá none (odpoví hned s login_required nebo consent_required, pokud by osoba musela něco udělat), login (požádá osobu o nové přihlášení) a consent (zobrazí obrazovku souhlasu, i když byl dříve udělen). max_age je podporováno. Zapamatovaný souhlas: pokud osoba dříve schválila stejné rozsahy, vrátí se rovnou do vaší aplikace. Pokud později požádáte o víc, obrazovka souhlasu uvede jen to, co je nové.

Rozsahy a claimy

Žádejte jen o to, co potřebujete. Nic mimo tuto tabulku neexistuje: žádné kontakty, žádné soubory, žádná hesla.

ScopeClaimy
openid (povinné)sub: náhodné ID osoby, stejné pro každou aplikaci vaší organizace a jiné pro každou jinou organizaci
profilename (je-li nastaveno) a locale
emailemail a email_verified (vždy true)
addressaddress (formatted, street_address, locality, region, postal_code, country), jen pokud ji osoba uložila
organisationsorganisations: organizace, které osoba zaškrtne na obrazovce souhlasu, každá s id, name, display_name, website, country, register_number, vat, vat_verified (true jen tehdy, když DIČ potvrdila služba EU VIES), verified, verification (viz Ověřené organizace) a role (owner, admin nebo member)
offline_accessžádné claimy; obdržíte také obnovovací token

Claimy se objevují v ID tokenu pro rozsahy, které osoba schválila. Koncový bod informací o uživateli vrací stejnou sadu s aktuálními hodnotami.

Ověřené organizace

Dazr ověří organizaci jen tehdy, když oficiální zdroje prokážou dvě věci: kdo daná osoba je a že zastupuje tuto organizaci s jejím názvem, číslem v rejstříku a DIČ. Obvykle jednatel podepíše krátké prohlášení kvalifikovaným elektronickým podpisem (QES) a přidá výpis z obchodního rejstříku, který ho uvádí; s výpisem zapečetěným rejstříkem, jako je italská visura nebo nizozemský výpis z KvK, je to okamžité, jinak ho zkontroluje Dazr. Samotný kvalifikovaný podpis nikdy organizaci ověřenou neučiní. Každá organizace v claimu organisations nese svůj aktuální stav ověření:

Ověření organizace v Dazr Identity: jednatel podepíše prohlášení kvalifikovaným podpisem hned nebo později e-mailem, nebo nahraje výpis z rejstříku a doklad totožnosti
verification.statusVýznam
unverifiedNeověřeno, nebo ověření selhalo, vypršelo nebo bylo zrušeno (například po změně obchodní firmy nebo čísla společnosti).
pendingOvěření probíhá: zástupce byl požádán o podpis, výpis z obchodního rejstříku stále chybí nebo Dazr kontroluje dokumenty. method říká, který způsob byl zahájen, například qes (zástupce podepíše prohlášení), qseal, pec, letter, video nebo documents.
verifiedOvěřeno. method je qes_org (kvalifikovaný podpis, certifikát uvádí organizaci), extract_sealed (kvalifikovaný podpis nebo zkontrolovaný doklad totožnosti plus výpis zapečetěný obchodním rejstříkem), qes_reviewed (kvalifikovaný podpis, výpis zkontrolovaný Dazr), qseal (kvalifikovaná elektronická pečeť organizace), documents, pec (kód zaslaný na adresu PEC organizace, Itálie), letter (kód zaslaný poštou do sídla), video (videohovor s Dazr) nebo extract. authority říká, co prokázalo, že osoba organizaci zastupuje (viz níže), a verified_at je čas Unix.

Jen když je stav verified, říká verification.authority (a authority ve webhoocích), jak bylo prokázáno spojení mezi osobou a organizací:

verification.authorityVýznam
certificateKvalifikovaný certifikát podepisujícího nebo kvalifikovaná pečeť organizace uvádí organizaci s číslem v rejstříku. Pokud certifikát obsahoval jen DIČ, číslo v rejstříku prokázal výpis z rejstříku.
register_extractVýpis zapečetěný obchodním rejstříkem, nejvýše 3 měsíce starý, uvádí organizaci s číslem v rejstříku a DIČ a podepisujícího jako jednatele nebo zákonného zástupce.
reviewedDazr zkontroloval výpis, který podepisujícího uvádí, nebo bez kvalifikovaného podpisu výpis a doklad totožnosti.
pecKód zaslaný na adresu PEC uvedenou ve visura zapečetěné rejstříkem (Itálie).
letterKód zaslaný poštou do sídla, poté co Dazr ověřil údaje podle rejstříku.
videoVideohovor s Dazr: doklad totožnosti a oficiální výpis, který osobu uvádí.

Logická hodnota verified zůstává kvůli kompatibilitě a rovná se verification.status === 'verified'. Každá organizace má také id, stejné, jaké používají webhooky.

Když je stav pending nebo verified, je verification.report_url adresou její zprávy o ověření.

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

role a členství se znovu načítají při každém obnovení tokenu a požadavku na informace o uživateli: po změně role nese další odpověď novou roli a organizace, ze které osoba odešla nebo byla odebrána, už není zahrnuta. Když administrátor organizace odpojí vaši aplikaci, organizace se vynechá z dříve vydaných tokenů, dokud ji člen při novém přihlášení s vaší aplikací znovu nesdílí. display_name a website jsou null, pokud je organizace nenastavila; name je vždy obchodní firma.

Vyžadovat ověřenou organizaci

V konzoli nastavte Vyžadovat ověřenou organizaci na Ověření zahájeno nebo Ověřeno, nebo o to požádejte u jednotlivého požadavku pomocí acr_values=urn:dazr:org:verification-started nebo acr_values=urn:dazr:org:verified (platí přísnější z obou). Vaše aplikace musí také žádat o rozsah organisations.

Nastavení Vyžadovat ověřenou organizaci ve vývojářské konzoli: nevyžadováno, ověření zahájeno nebo ověřeno

Kdo nemá vyhovující organizaci, projde tím ve stejném přihlášení: jméno, organizace (s DIČ ověřeným ve VIES) a pak ověření. Může podepsat hned, nechat si prohlášení poslat e-mailem nebo určit někoho jiného, kdo podepíše. Poté zaškrtne organizaci na obrazovce souhlasu (zaškrtnout lze jen vyhovující organizace) a vrátí se na vaše URI pro přesměrování.

Pokud musí podepsat ještě někdo jiný, osoba se vrátí se stavem pending, i když jste požádali o Ověřeno: obdržíte kód, claim uvádí pending a acr v ID tokenu je urn:dazr:org:verification-started místo urn:dazr:org:verified. Vždy rozhodujte podle verification.status, nikdy podle toho, že přihlášení proběhlo úspěšně. S prompt=none dostanete interaction_required, když požadavek není splněn.

Změny nastavení platí od dalšího přihlášení. Již přihlášení lidé se neodhlásí: odpovědi při obnovení, koncový bod informací o uživateli a webhooky vždy nesou aktuální stav, proto na ně u existujících relací reagujte.

Webhooky

Přidejte v konzoli URL webhooku (https). Podpisové tajemství uvidíte jednou; můžete ho vyměnit. Dazr posílá organisation.verification.updated, když organizace, kterou některý z vašich uživatelů sdílel s vaší aplikací, přejde do stavu pending, verified, failed nebo unverified. Aplikace, které nikdy neobdržely organizaci prostřednictvím souhlasu, se o ní nikdy nedozvědí.

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", "authority": "certificate", "verified_at": 1791021598,
            "report_url": "https://identity.dazr.eu/oauth/verification-report?org=org_3k9x2m0q8w1v5t7a",
            "subjects": ["Xo1c…"] } }

status je pending, verified, failed nebo unverified. subjects jsou hodnoty sub ve vaší aplikaci u lidí, kteří s ní tuto organizaci sdíleli. Než tělu požadavku začnete důvěřovat, ověřte podpis:

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]));
}

Odpovězte jakýmkoli kódem 2xx do 8 sekund. Jinak Dazr zkusí doručení znovu přibližně po 5 minutách, 30 minutách, 2, 6, 12 a 24 hodinách a pak doručení označí jako neúspěšné. Každý pokus má stejné ID Dazr-Delivery, takže duplikáty ignorujte. Konzole zobrazuje nedávná doručení, umí jedno znovu odeslat a může poslat testovací událost (webhook.test). Funguje i dotazování koncového bodu informací o uživateli.

Zprávy o ověření pro audity

Pro každou organizaci sdílenou s vaší aplikací si můžete stáhnout zprávu o tom, jak a kdy ji Dazr ověřil, do svého auditního spisu. Existuje, dokud je organizace ověřena, a během probíhajícího ověření, kdy ukazuje, co je zatím hotovo.

Zpráva nikdy neobsahuje snímky ani čísla dokladů totožnosti, jednorázové kódy, adresu PEC, e-mailové adresy ani jinou adresu než sídlo.

Stažení zprávy

Ověřte se svým client ID a tajemstvím klienta, stejně jako u tokenového koncového bodu: HTTP Basic (client_secret_basic) nebo tělo formuláře požadavku POST (client_secret_post). Nikdy nevkládejte tajemství do URL. Použijte id organizace z claimů nebo webhooků, nebo jednoduše verification.report_url, které obsahují.

curl -u "$DAZR_CLIENT_ID:$DAZR_CLIENT_SECRET" -o report.pdf \
  "https://identity.dazr.eu/oauth/verification-report?org=org_3k9x2m0q8w1v5t7a&format=pdf&lang=en"
ParametrVýznam
orgid organizace.
formatpdf (výchozí) nebo jws, stejná fakta jako podepsaný JSON.
langJazyk PDF: en (výchozí), nl, it, de, fr, es nebo pl.
docMísto zprávy: declaration, podepsané prohlášení jednatele (jen kvalifikovaný podpis nebo pečeť), nebo extract, výpis z obchodního rejstříku.

Stáhnout lze jen organizace, které s vaší aplikací prostřednictvím souhlasu sdílel alespoň jeden z vašich uživatelů. Jakákoli jiná organizace odpoví 404, stejně jako organizace, která neexistuje nebo nemá ověření; chybné tajemství klienta odpoví 401. Aplikace bez tajemství klienta nemohou zprávy stahovat. Stahování má omezený počet požadavků a každé se zobrazí v aktivitě organizace jejím administrátorům, s názvem vaší aplikace. V konzoli stránka vaší aplikace uvádí propojené organizace se stejnými možnostmi stažení.

Ověření podepsaného JSON

S format=jws obdržíte kompaktní JWS (ES256, hlavička typ dazr-verification-report+jwt), podepsaný stejnými klíči jako ID tokeny. Jeho claimy jsou iss, iat, jti (ID dokumentu), sub (id organizace), aud (vaše client ID) a report, fakta. PDF nese stejný JWS na poslední stránce a v metadatech (DazrVerificationReport), takže i PDF lze ověřit offline.

import { createRemoteJWKSet, jwtVerify } from 'jose';

const jwks = createRemoteJWKSet(new URL('https://identity.dazr.eu/oauth/jwks'));
// jws = the response body of format=jws, or the text from the PDF metadata
const { payload } = await jwtVerify(jws, jwks, {
  issuer: 'https://identity.dazr.eu',
  audience: process.env.DAZR_CLIENT_ID,
  typ: 'dazr-verification-report+jwt',
});
console.log(payload.report.verification.status, payload.report.verification.authority);

Nechte auditora ověřit podpis

U kvalifikovaného podpisu nebo pečeti vrací doc=declaration podepsané prohlášení přesně tak, jak bylo nahráno: podepsané PDF (PAdES) nebo soubor .p7m (CAdES). Auditor ho může nezávisle ověřit ukázkovým validátorem DSS Evropské komise: nahrajte soubor, ponechte výchozí validační politiku a spusťte ho. Výsledek ukáže, zda je podpis kvalifikovaný (QESig, u pečeti QESeal), kdo podepsal a poskytovatele služeb vytvářejících důvěru z důvěryhodného seznamu EU. doc=extract vrací výpis z obchodního rejstříku; výpis zapečetěný rejstříkem lze ověřit stejným způsobem.

Zpráva je důkazem pro váš auditní spis. Regulované firmy zůstávají odpovědné za vlastní hloubkovou kontrolu zákazníků.

Dazr uchovává podepsané prohlášení, výpis a data zprávy, dokud je organizace ověřena, a 5 let po skončení jejího ověření nebo smazání organizace. Vlastní kopie si uchovávejte tak dlouho, jak vyžadují vaše pravidla.

Tokeny a jejich platnost

TokenPlatnost a pravidla
Autorizační kód60 sekund, jednorázový, vázaný na vašeho klienta, URI pro přesměrování a výzvu PKCE. Použití kódu dvakrát zneplatní tokeny, které vydal.
Přístupový token10 minut. Podepsaný JWT (ES256, typ at+jwt) s aud = vaše client ID. Posílejte ho jako Authorization: Bearer.
ID token10 minut. ES256, s iss, sub, aud, exp, iat, auth_time, nonce a amr, pokud je znám.
Obnovovací tokenJen s offline_access. Při každém použití se mění: vždy uložte nový. Opětovné odeslání starého obnovovacího tokenu zneplatní celé přihlášení. Vyprší po 30 dnech bez použití, nejpozději po 180 dnech.

Podpisové klíče se mění. Vždy vybírejte klíč podle kid z JWKS a JWKS obnovte, když uvidíte neznámé kid.

Chyby

Dokud jsou vaše client ID a URI pro přesměrování platné, chyby se vracejí na vaše URI pro přesměrování jako error, error_description, state a iss: například invalid_request (třeba chybějící nebo plain PKCE), invalid_scope, unsupported_response_type, access_denied (osoba akci zrušila, nebo je aplikace v testování a osoba není členem), login_required, consent_required a interaction_required (s prompt=none, když chybí požadovaná ověřená organizace). U neznámého klienta nebo neregistrovaného URI pro přesměrování zobrazí Dazr chybovou stránku a nikdy nepřesměruje. Tokenový koncový bod odpovídá chybami ve formátu JSON, například invalid_client, invalid_grant a unsupported_grant_type.

Odhlášení

Chcete-li někoho odhlásit, pošlete ho na koncový bod odhlášení s id_token_hint (nebo client_id), volitelným post_logout_redirect_uri registrovaným v nastavení aplikace a state. Dazr se zeptá, zda se chce na tomto zařízení odhlásit i z Dazr Identity, a pak ho pošle zpět. Obnovovací tokeny, které už nepotřebujete, zneplatněte na koncovém bodu pro zneplatnění.

Testování a spuštění

Nová aplikace je v testování: přihlásit se mohou jen členové vaší organizace a obrazovka souhlasu to uvádí. Ke spuštění nechte svou organizaci ověřit v Dazr Identity, přidejte URI pro přesměrování https:// a v konzoli požádejte o kontrolu pro spuštění. Změna názvu, účelu, zásad ochrany osobních údajů nebo údajů spuštěné aplikace vyžaduje novou kontrolu.

Převod aplikace na jinou organizaci

Aplikace se může přesunout k jiné organizaci registrované v Dazr, například po prodeji nebo reorganizaci. Převod zahájí vlastník nebo administrátor v části Převést aplikaci v nastavení aplikace, v Dazr Identity nebo v portálu Sign. Vlastník nebo administrátor druhé organizace ho do 14 dnů přijme nebo odmítne. Do té doby může odesílatel převod zrušit a nic se nemění.

Tlačítko

Použijte text „Přihlásit se přes Dazr Identity“ a logo Dazr podle ukázky níže. Velikost můžete změnit, logo, barvy ani text ne. Propojte ho s vlastní trasou, která spustí tok.

<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 'Dazr', 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>

Písmo Dazr. Tlačítko používá písmo Dazr, které lze volně používat podle SIL Open Font License. Kde písmo Dazr není načteno, použije se systémové písmo. Stáhněte si písmo Dazr (ZIP se soubory TTF a WOFF2) a hostujte ho na vlastním webu:

/* woff2 files from the ZIP, copied to /fonts/ on your site */
@font-face { font-family: 'Dazr'; font-weight: 400; font-display: swap;
  src: url('/fonts/dazr-regular-latin.woff2') format('woff2'); }
@font-face { font-family: 'Dazr'; font-weight: 700; font-display: swap;
  src: url('/fonts/dazr-bold-latin.woff2') format('woff2'); }
.dazr-signin { font: 600 15px/1 'Dazr', system-ui, sans-serif; }

Minimální příklad v Node.js

Node 18 nebo novější, bez závislostí. Webová serverová aplikace s tajemstvím klienta; u veřejného klienta vynechte hlavičku Authorization a pošlete client_id v těle.

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

Autorizační a tokenový koncový bod mají omezený počet požadavků. Pokud dostanete HTTP 429, počkejte a zkuste to znovu; neopakujte požadavky v rychlé smyčce.

Vaše povinnosti

Vaše organizace je pro údaje, které obdrží, samostatným správcem. Podmínky pro vývojáře Dazr Identity stanoví, co s nimi smíte dělat, jak je zabezpečit a jak hlásit porušení. Dotazy: hello@dazr.eu.