Logga in med Dazr Identity: utvecklardokumentation

Människor kan redan använda sitt Google- eller Microsoft-konto i Dazr Identity, så din app behöver inga separata Google- och Microsoft-knappar bredvid: en knapp i stället för tre.

Discovery och endpoints

Allt beskrivs i discovery-dokumentet. Peka ditt bibliotek mot utfärdaren så hittar det resten.

VadAdress
Utfärdare (issuer)https://identity.dazr.eu
Discoveryhttps://identity.dazr.eu/.well-known/openid-configuration
Auktoriseringhttps://identity.dazr.eu/oauth/authorize
Tokenhttps://identity.dazr.eu/oauth/token
Användaruppgifterhttps://identity.dazr.eu/oauth/userinfo
Offentliga nycklar (JWKS)https://identity.dazr.eu/oauth/jwks
Återkallelse (RFC 7009)https://identity.dazr.eu/oauth/revoke
Introspektion (RFC 7662), bara webbserverapparhttps://identity.dazr.eu/oauth/introspect
Logga ut (RP-initiated logout)https://identity.dazr.eu/oauth/logout
Verifieringsrapporter, bara webbserverapparhttps://identity.dazr.eu/oauth/verification-report

Registrera en app

En app i utvecklarkonsolen för Dazr Identity: klient-id, discovery-URL, omdirigerings-URI:er, scopes och stegen för att ansluta den

Integrationsguider

Varje stack nedan använder sitt eget standardstöd för OpenID Connect. Du behöver tre värden från konsolen: klient-id:t, klienthemligheten (bara webbserverappar) och den omdirigerings-URI du registrerade. Resten kommer från discovery-dokumentet.

Auth.js / NextAuth

Auth.js (NextAuth.js v5) tar ett anpassat OpenID Connect-providerobjekt. Registrera en webbserverapp, ange AUTH_SECRET, AUTH_DAZR_ID och AUTH_DAZR_SECRET och använd den här callback-URL:en som omdirigerings-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 använder samma idé med type: "oauth" och discovery-URL:en:

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

Med filen auth.ts ovan lägger du till route-hanteraren och en inloggningsknapp som kör en 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>
  )
}

Utforma knappen som visas under Knappen. I callbacks är Dazrs sub lika med account.providerAccountId.

WordPress

Använd ett generiskt OpenID Connect-klienttillägg, t.ex. OpenID Connect Generic Client. Registrera en webbserverapp och fyll i tilläggets inställningar med värdena nedan. Tillägget visar den omdirigerings-URI som ska registreras på sin inställningssida; som standard är den https://example.com/wp-admin/admin-ajax.php?action=openid-connect-authorize.

InställningVärde
Klient-idditt klient-id
Klienthemlighetdin klienthemlighet
Scopeopenid profile email
Inloggnings-endpoint (auktorisering)https://identity.dazr.eu/oauth/authorize
Token-endpointhttps://identity.dazr.eu/oauth/token
Endpoint för användaruppgifterhttps://identity.dazr.eu/oauth/userinfo
Endpoint för avslutning av sessionhttps://identity.dazr.eu/oauth/logout
Identitetsnyckelsub
PKCEpå (S256)

Namnen på inställningarna skiljer sig lite mellan tillägg. Har ett tillägg inget PKCE-alternativ, välj ett annat: Dazr Identity avvisar inloggningar utan PKCE.

Laravel

Laravel Socialite har ingen inbyggd generisk OpenID Connect-drivrutin, så lägg till en liten anpassad drivrutin. Den skickar människor till Dazr med PKCE och läser användaren från endpointen för användaruppgifter. Socialite läser inte discovery-dokumentet, så endpoints är utskrivna. Registrera en webbserverapp med omdirigerings-URI: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 har ingen generisk OpenID Connect-provider som du kan peka mot vilken utfärdare som helst: dess inloggningsleverantörer och integrationer med tredjeparts-auth är fasta listor. Så du kan inte lägga till Dazr Identity i Supabase-instrumentpanelen i dag. Om Supabase lägger till generiskt stöd för OpenID Connect, använd värdena från checklistan nedan.

Alternativet: logga in människor med Dazr Identity på din egen server (med en av guiderna på den här sidan), spara Dazrs sub i din användartabell och prata med Supabase från den servern med service role-nyckeln, medan du kontrollerar åtkomst i din egen kod. Skicka aldrig service role-nyckeln till en webbläsare.

Django

Använd mozilla-django-oidc. Registrera en webbserverapp med omdirigerings-URI:n https://app.example.eu/oidc/callback/. Biblioteket läser inte discovery-dokumentet, så endpoints är utskrivna.

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

Som standard matchar backenden användare efter e-post. För att använda sub som kontonyckel gör du en underklass av OIDCAuthenticationBackend och skriver över filter_users_by_claims och create_user. Använd en aktuell version: äldre versioner kan inte verifiera ES256-signaturer.

Node.js (openid-client)

openid-client (version 6) läser discovery-dokumentet och kontrollerar PKCE, state, nonce och ID-token åt dig.

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

Vilket OpenID Connect-bibliotek som helst

Finns din stack inte på listan fungerar vilken OpenID Connect-klient som helst. Kontrollera dessa inställningar:

Flödet

  1. Skapa en slumpmässig code_verifier (43 till 128 tecken) och dess code_challenge = base64url(SHA-256(verifier)). Skapa en slumpmässig state och nonce. Spara alla tre i användarens session.
  2. Omdirigera till authorization-endpointen med response_type=code, client_id, redirect_uri, scope (alltid inklusive openid), state, nonce, code_challenge och code_challenge_method=S256.
  3. Personen loggar in om det behövs och ser samtyckesskärmen med de faktiska uppgifterna. När personen tillåter det kommer hen tillbaka till din omdirigerings-URI med code, state och iss. Kontrollera att state matchar och att iss är https://identity.dazr.eu.
  4. På din server gör du en POST till token-endpointen med grant_type=authorization_code, code, samma redirect_uri och code_verifier.
  5. Verifiera ID-token: ES256-signatur med en nyckel från JWKS (matcha kid), iss, aud = ditt klient-id, exp och din nonce. Använd sub som kontonyckel.
Samtyckesskärmen i Dazr Identity för en app som heter Ledgerline: den visar namnet, e-postadressen och den verifierade organisation som användaren valde att dela

Parametern prompt accepterar none (svara direkt med login_required eller consent_required om personen skulle behöva agera), login (be personen logga in igen) och consent (visa samtyckesskärmen även när den har godkänts tidigare). max_age stöds. Ihågkommet samtycke: om personen har godkänt samma scopes tidigare går hen direkt tillbaka till din app. Ber du om mer senare visar samtyckesskärmen bara det nya.

Scopes och claims

Be bara om det du behöver. Inget utanför den här tabellen finns: inga kontakter, inga filer, inga lösenord.

ScopeClaims
openid (krävs)sub: ett slumpmässigt id för personen, detsamma för alla appar i din organisation och olika för alla andra organisationer
profilename (om angivet) och locale
emailemail och email_verified (alltid true)
addressaddress (formatted, street_address, locality, region, postal_code, country), bara om personen har sparat en
organisationsorganisations: de organisationer som personen markerar på samtyckesskärmen, var och en med id, name, display_name, website, country, register_number, vat, vat_verified (bara true när EU:s VIES-tjänst har bekräftat momsregistreringsnumret), verified, verification (se Verifierade organisationer) och role (owner, admin eller member)
offline_accessinga claims; du får också en refresh-token

Claims visas i ID-token för de scopes som personen godkände. Endpointen för användaruppgifter returnerar samma uppsättning med aktuella värden.

Verifierade organisationer

Dazr verifierar bara en organisation när officiella källor bevisar två saker: vem personen är och att personen företräder den här organisationen, med dess namn, registreringsnummer och momsregistreringsnummer. Typiskt undertecknar vd:n en kort försäkran med en kvalificerad elektronisk signatur (QES) och lägger till utdraget från företagsregistret som nämner hen; med ett utdrag förseglat av registret, som den italienska visuran eller ett nederländskt KvK-utdrag, sker det direkt, annars granskar Dazr det. En kvalificerad signatur ensam gör aldrig en organisation verifierad. Varje organisation i claimet organisations har sin aktuella verifiering:

Verifiering av en organisation i Dazr Identity: vd:n undertecknar försäkran med en kvalificerad signatur nu eller senare via e-post, eller laddar upp företagsutdraget och ett id
verification.statusBetydelse
unverifiedInte verifierad, eller en verifiering misslyckades, gick ut eller återkallades (t.ex. efter att det juridiska namnet eller organisationsnumret ändrades).
pendingVerifieringen pågår: företrädaren har ombetts att underteckna, utdraget från företagsregistret saknas fortfarande, eller Dazr granskar dokument. method anger vilken väg som påbörjades, t.ex. qes (företrädaren undertecknar försäkran), qseal, pec, letter, video eller documents.
verifiedVerifierad. method är qes_org (kvalificerad signatur, certifikatet nämner organisationen), extract_sealed (kvalificerad signatur eller granskat id plus ett utdrag förseglat av företagsregistret), qes_reviewed (kvalificerad signatur, utdrag kontrollerat av Dazr), qseal (organisationens kvalificerade elektroniska stämpel), documents, pec (en kod som skickats till organisationens PEC-adress, Italien), letter (en kod som skickats med posten till det registrerade sätet), video (ett videosamtal med Dazr) eller extract. authority anger vad som bevisade att personen företräder organisationen (se nedan), och verified_at är en Unix-tidpunkt.

Bara när status är verified anger verification.authority (och authority i webhooks) hur kopplingen mellan personen och organisationen bevisades:

verification.authorityBetydelse
certificateUndertecknarens kvalificerade certifikat eller organisationens kvalificerade stämpel nämner organisationen med dess registreringsnummer. Med bara ett momsregistreringsnummer i certifikatet bevisade ett registerutdrag registreringsnumret.
register_extractEtt utdrag förseglat av företagsregistret, högst 3 månader gammalt, nämner organisationen med dess registrerings- och momsregistreringsnummer och anger undertecknaren som vd eller juridisk företrädare.
reviewedDazr kontrollerade ett utdrag som nämner undertecknaren eller, utan kvalificerad signatur, utdraget och ett id.
pecEn kod som skickats till PEC-adressen på visuran förseglad av registret (Italien).
letterEn kod som skickats med posten till det registrerade sätet, efter att Dazr hade kontrollerat uppgifterna mot registret.
videoEtt videosamtal med Dazr: ett id och ett officiellt utdrag som nämner personen.

Booleanen verified behålls av kompatibilitetsskäl och är lika med verification.status === 'verified'. Varje organisation har också ett id, samma som webhooks använder.

När status är pending eller verified är verification.report_url adressen till dess verifieringsrapport.

"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 och medlemskap läses om vid varje förnyelse av token och varje begäran om användaruppgifter: efter en rolländring har nästa svar den nya rollen, och en organisation som personen har lämnat eller tagits bort från finns inte längre med. När en administratör för organisationen kopplar bort din app utelämnas organisationen från tidigare utfärdade tokens tills en medlem delar den med din app igen vid en ny inloggning. display_name och website är null när organisationen inte har angett dem; name är alltid det juridiska namnet.

Kräv en verifierad organisation

Ställ i konsolen in Kräv en verifierad organisation på Verifiering påbörjad eller Verifierad, eller be om det per förfrågan med acr_values=urn:dazr:org:verification-started eller acr_values=urn:dazr:org:verified (den striktaste av de två vinner). Din app måste också begära scopet organisations.

Inställningen Kräv en verifierad organisation i utvecklarkonsolen: krävs inte, verifiering påbörjad eller verifierad

En person utan en kvalificerande organisation tas igenom det i samma inloggning: namnet, organisationen (med momsregistreringsnumret kontrollerat i VIES) och sedan verifieringen. Personen kan underteckna direkt, få försäkran skickad till sig själv via e-post eller ange någon annan som undertecknar. Därefter markerar personen organisationen på samtyckesskärmen (bara kvalificerande organisationer kan markeras) och återvänder till din omdirigerings-URI.

Måste någon annan fortfarande underteckna kommer personen tillbaka med status pending, även när du bad om Verifierad: du får en kod, claimet säger pending, och ID-tokens acr är urn:dazr:org:verification-started i stället för urn:dazr:org:verified. Styr alltid åtkomst efter verification.status, aldrig efter att inloggningen lyckades. Med prompt=none får du interaction_required när kravet inte är uppfyllt.

Ändringar av inställningen gäller från nästa inloggning. Människor som redan är inloggade loggas inte ut: svar på förnyelser, endpointen för användaruppgifter och webhooks har alltid aktuell status, så använd dem för att reagera för befintliga sessioner.

Webhooks

Lägg till en webhook-URL (https) i konsolen. Du ser signeringshemligheten en gång; du kan rotera den. Dazr skickar organisation.verification.updated när en organisation som någon av dina användare har delat med din app blir pending, verified, failed eller unverified. Appar som aldrig har fått en organisation via samtycke får aldrig höra om det.

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 är pending, verified, failed eller unverified. subjects är sub-värdena i din app för de personer som har delat den här organisationen med den. Kontrollera signaturen innan du litar på body:n:

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

Svara med vilken 2xx som helst inom 8 sekunder. Annars försöker Dazr igen efter ungefär 5 minuter, 30 minuter, 2, 6, 12 och 24 timmar och markerar sedan leveransen som misslyckad. Varje försök har samma Dazr-Delivery-id, så ignorera dubbletter. Konsolen visar de senaste leveranserna, kan skicka en igen och kan skicka en testhändelse (webhook.test). Polling av endpointen för användaruppgifter fungerar också.

Företagsverifiering (KYB)

Företagsverifiering är den högre tillitsnivån ovanpå organisationsverifiering. Den lägger till vem som äger och leder företaget: företagsregistret, en ID-kontroll med selfie för företrädaren och för varje verklig huvudman, ägarstrukturen samt screening för sanktioner och PEP. Organisationen betalar 25 € exkl. moms, en gång; avbryter den innan någon ID-handling har kontrollerats återbetalas hela beloppet.

Företagsverifiering på organisationens sida: stegen, företrädarens ID-kontroll, resultatet från registret och ägarna med sina andelar
  1. Företagsuppgifter. Den juridiska formen samt registreringsnummer och säte från organisationens juridiska uppgifter, bekräftade av den som startar verifieringen.
  2. Betalning. 25 € exkl. moms via Mollie; fakturan finns på organisationens sida.
  3. ID-handling och selfie. Företrädaren fotograferar ett pass, ID-kort eller uppehållstillstånd (fram- och baksida vid behov) och tar två selfies, den andra med en slumpmässig vridning eller lutning av huvudet. En AI-modell läser handlingen; Dazr kontrollerar den maskinläsbara zonen (kontrollsiffror enligt ICAO 9303), datumen och namnet; en tjänst för ansiktsjämförelse jämför selfien med fotot i handlingen. En QR-kod flyttar fotograferingen från en dator till en telefon.
  4. Kontroll i företagsregistret. Namn, status och ledning från det officiella registret där det finns online (Norge, Danmark, Finland, Frankrike, Nederländerna, Polen, Tjeckien och Storbritannien, inklusive dess register över personer med betydande kontroll), annars från ett officiellt utdrag som är högst 3 månader gammalt.
  5. Vem äger företaget? Varje person med 25 % eller mer av andelarna eller rösterna, direkt eller via andra bolag (med kedjan), eller med kontroll på annat sätt. Uppfyller ingen detta räknas ledningen som verkliga huvudmän.
  6. Ägarna verifierar. Varje ägare får en länk med e-post, bekräftar den med en engångskod och gör samma ID-kontroll. Påminnelser skickas efter 2 och 7 dagar; länkar går ut efter 14 dagar.
  7. Sanktions- och PEP-kontroller. Företaget och varje person mot EU:s, FN:s och OFAC:s sanktionslistor och för politiskt exponerade personer.
  8. Beslut. Dokumenterade riskregler godkänner ärenden utan anmärkning. Allt annat går till en granskare på Dazr, som kan godkänna, avslå med en motivering, be organisationen om mer information eller köra en kontroll igen. Högriskärenden kräver två granskare. Inget ärende avslås automatiskt.

Godkända organisationer screenas mot sanktionslistorna igen varje dag och för PEP-status regelbundet. En ny träff skickar tillbaka verifieringen till granskning, och din app får veta det.

Claimet kyb

Varje organisation i claimet organisations innehåller kyb, och verification.assurance_level sammanfattar båda nivåerna: none, basic (organisationen verifierad) eller kyb (företagsverifiering godkänd).

kyb.statusBetydelse
noneIngen företagsverifiering, eller så avbröts den senaste eller gick ut.
in_progressPåbörjad: organisationen går igenom stegen, eller ägare behöver fortfarande få sin ID-handling kontrollerad.
in_reviewInskickad och under granskning hos Dazr, eller tillbaka i granskning efter en ny träff i screeningen.
approvedGodkänd. Först då innehåller claimet verified_claims.
rejectedInte godkänd. Organisationen kan starta en ny.

Efter godkännande följer verified_claims formatet OpenID Connect for Identity Assurance:

"kyb": {
  "status": "approved",
  "report_url": "https://identity.dazr.eu/oauth/verification-report?org=org_3k9x2m0q8w1v5t7a",
  "verified_claims": {
    "verification": {
      "trust_framework": "dazr_kyb", "assurance_level": "kyb", "time": "2026-10-06T09:14:03.000Z",
      "verification_process": "kyb_7Tq2…",
      "evidence": [
        { "type": "electronic_record", "check_details": [{ "check_method": "data", "organization": "no-brreg" }] },
        { "type": "document", "check_details": [{ "check_method": "vpip" }, { "check_method": "pvr" }],
          "note": "ID document and selfie with liveness of the representative and each beneficial owner" }
      ]
    },
    "claims": {
      "legal_name": "Fjordline Logistikk AS", "country": "NO", "registration_number": "912345678",
      "beneficial_owners_verified": 2,
      "screening": { "result": "no_match_found", "pep_checked": true, "last_screened_at": "2026-10-06T03:23:00.000Z" },
      "risk_level": "low"
    }
  }
}

Claimet innehåller aldrig namn, födelsedatum eller dokumentuppgifter om ägarna. De finns i revisionsrapporten, som din app kan hämta för organisationer som delats med den.

Kräva företagsverifiering

Ställ i konsolen in Kräv en verifierad organisation på Företagsverifiering (KYB), eller be om det per begäran med acr_values=urn:dazr:org:kyb. Den som inte har det än startar det i samma inloggning och kan fortsätta till din app direkt efteråt; de återstående stegen, som ägarnas ID-kontroller, sker senare. ID-tokenets acr är urn:dazr:org:kyb först när en organisation är godkänd, så kontrollera alltid kyb.status === 'approved' innan du låser upp något som kräver det.

Webhooks för företagsverifiering

Samma händelse organisation.verification.updated skickas när statusen för företagsverifieringen ändras, även efter en ny screening. Dess data innehåller dessutom:

"kyb": { "status": "approved", "approved_at": 1791021598, "risk_level": "low" },
"assurance_level": "kyb"

Företagsverifiering på egen hand

En organisation kan också starta företagsverifiering från sin sida i Dazr Identity, utan att någon app ber om det. Resultatet är detsamma: en verifiering per organisation, som varje app som organisationen delas med kan lita på. Bilder av ID-handlingar och selfies raderas 30 dagar efter beslutet; resultaten och rapporten sparas i 5 år efter att verifieringen har upphört, som penningtvättsreglerna kräver.

Verifieringsrapporter för revisioner

För varje organisation som har delats med din app kan du hämta en rapport om hur och när Dazr verifierade den, för din revisionsakt. Den finns medan organisationen är verifierad och medan verifieringen pågår, och visar då det som har gjorts hittills.

En rapport innehåller aldrig bilder eller nummer från identitetshandlingar, engångskoder, PEC-adressen, e-postadresser eller andra adresser än det registrerade sätet.

Hämta en rapport

Autentisera med ditt klient-id och din klienthemlighet, som vid token-endpointen: HTTP Basic (client_secret_basic) eller formulärets body i en POST (client_secret_post). Lägg aldrig hemligheten i URL:en. Använd organisationens id från claims eller webhooks, eller helt enkelt den verification.report_url som de innehåller.

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"
ParameterBetydelse
orgOrganisationens id.
formatpdf (standard) eller jws, samma fakta som signerad JSON.
langPDF:ens språk: en (standard), nl, it, de, fr, es eller pl.
docI stället för rapporten: declaration, vd:ns signerade försäkran (bara kvalificerad signatur eller stämpel), eller extract, utdraget från företagsregistret.

Bara organisationer som minst en av dina användare har delat med din app via samtycke kan hämtas. Varje annan organisation svarar 404, precis som en som inte finns eller inte har någon verifiering; en felaktig klienthemlighet svarar 401. Appar utan klienthemlighet kan inte hämta rapporter. Nedladdningar är hastighetsbegränsade, och varje nedladdning visas i organisationens aktivitet för dess administratörer med din apps namn. I konsolen visar din apps sida de anslutna organisationerna med samma nedladdningar.

Verifiera den signerade JSON:en

Med format=jws får du en kompakt JWS (ES256, huvud typ dazr-verification-report+jwt), signerad med samma nycklar som ID-tokens. Dess claims är iss, iat, jti (dokument-id:t), sub (organisationens id), aud (ditt klient-id) och report, fakta. PDF:en innehåller samma JWS på sista sidan och i sina metadata (DazrVerificationReport), så att en PDF också kan kontrolleras 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);

Låt en revisor kontrollera signaturen

För en kvalificerad signatur eller en kvalificerad stämpel returnerar doc=declaration den signerade försäkran exakt som den laddades upp: en signerad PDF (PAdES) eller en .p7m-fil (CAdES). En revisor kan validera den oberoende med Europeiska kommissionens DSS-demovaliderare: ladda upp filen, behåll standardpolicyn för validering och kör den. Resultatet visar om signaturen är kvalificerad (QESig, eller QESeal för en stämpel), vem som undertecknade och tillhandahållaren av betrodda tjänster från EU:s förtroendelista. doc=extract returnerar utdraget från företagsregistret; ett registerförseglat utdrag kan valideras på samma sätt.

Rapporten är underlag för din revisionsakt. Reglerade företag ansvarar fortfarande för sina egna rutiner för kundkännedom.

Dazr sparar den signerade försäkran, utdraget och rapportdata medan organisationen är verifierad och i 5 år efter att dess verifiering upphör eller organisationen raderas. Spara egna kopior så länge dina regler kräver det.

Tokens och livslängder

TokenLivslängd och regler
Auktoriseringskod60 sekunder, engångsanvändning, bunden till din klient, omdirigerings-URI och PKCE-challenge. Används en kod två gånger återkallas de tokens den utfärdade.
Access token10 minuter. En signerad JWT (ES256, typ at+jwt) med aud = ditt klient-id. Skicka den som Authorization: Bearer.
ID-token10 minuter. ES256, med iss, sub, aud, exp, iat, auth_time, nonce och amr, där det är känt.
Refresh tokenBara med offline_access. Roterar vid varje användning: spara alltid den nya. Skickas en gammal refresh token igen återkallas hela inloggningen. Går ut efter 30 dagar utan användning och senast efter 180 dagar.

Signeringsnycklar roterar. Välj alltid nyckeln efter kid från JWKS och uppdatera JWKS när du ser ett okänt kid.

Fel

Så länge ditt klient-id och din omdirigerings-URI är giltiga kommer fel tillbaka till din omdirigerings-URI som error, error_description, state och iss: t.ex. invalid_request (som saknad eller plain PKCE), invalid_scope, unsupported_response_type, access_denied (personen avbröt, eller appen är i testläge och personen är inte medlem), login_required, consent_required och interaction_required (med prompt=none, när en krävd verifierad organisation saknas). Med en okänd klient eller en oregistrerad omdirigerings-URI visar Dazr en felsida och omdirigerar aldrig. Token-endpointen svarar med JSON-fel som invalid_client, invalid_grant och unsupported_grant_type.

Logga ut

För att logga ut en person skickar du hen till utloggnings-endpointen med id_token_hint (eller client_id), en valfri post_logout_redirect_uri som är registrerad i din apps inställningar och state. Dazr frågar om personen också vill logga ut från Dazr Identity på den enheten och skickar sedan tillbaka hen. Återkalla refresh tokens som du inte längre behöver vid revocation-endpointen.

Test och lansering

En ny app är i testläge: bara medlemmar i din organisation kan logga in, och det står på samtyckesskärmen. För att gå live måste du få din organisation verifierad i Dazr Identity, lägga till en https://-omdirigerings-URI och begära en live-granskning i konsolen. Ändring av namn, ändamål, integritetspolicy eller data för en live-app kräver en ny granskning.

Överför en app till en annan organisation

En app kan flyttas till en annan organisation som är registrerad hos Dazr, t.ex. efter en försäljning eller en omorganisation. En ägare eller administratör startar överföringen under Överför app i appens inställningar, i Dazr Identity eller i Sign-portalen. En ägare eller administratör för den andra organisationen godtar eller avvisar den inom 14 dagar. Fram till dess kan avsändaren avbryta, och inget ändras.

Knappen

Använd formuleringen "Logga in med Dazr Identity" och Dazr-logotypen som nedan. Du får ändra storleken, inte logotypen, färgerna eller formuleringen. Länka den till din egen route som startar flödet.

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

Dazr-typsnittet. Knappen använder Dazr-typsnittet, som är fritt att använda under SIL Open Font License. Där Dazr inte är inläst används systemtypsnittet i stället. Ladda ned Dazr-typsnittet (ZIP med TTF- och WOFF2-filer) för att lagra det på din egen webbplats:

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

Ett minimalt Node.js-exempel

Node 18 eller senare, inga beroenden. En webbserverapp med klienthemlighet; för en offentlig klient tar du bort Authorization-huvudet och skickar client_id i body:n.

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

Gränser

Authorization- och token-endpointerna är hastighetsbegränsade. Får du HTTP 429, vänta och försök igen; försök inte igen i en tät loop.

Dina skyldigheter

Din organisation är självständigt personuppgiftsansvarig för de uppgifter den får. Utvecklarvillkoren för Dazr Identity fastställer vad du får göra med dem, hur du håller dem säkra och hur du rapporterar incidenter. Frågor: hello@dazr.eu.