Siirry pääsisältöön

OpenID4VCI-credentialin myöntäminen selitettynä: tarjouksesta hyväksyttyyn credentialiin

OpenID4VCI, OpenID for Verifiable Credential Issuance, määrittelee, miten wallet pyytää ja vastaanottaa credentialin myöntäjältä. Yksittäinen myöntäminen kulkee useiden erillisten vaiheiden läpi, ennen kuin walletilla on todella käyttökelpoinen credential, ja jokaisella vaiheella on oma epäonnistumistapansa. Tämä sivu käy läpi koko tämän elinkaaren, alkuperäisten esimerkkien avulla.

Kaksi tapaa aloittaa: pre-authorized code ja authorization code

Myöntäminen alkaa usein myöntäjän lähettämästä Credential Offer -tarjouksesta, ja sen nimeämä grant ratkaisee, miten wallet valtuutetaan. Wallet voi myös aloittaa myöntämisen itse, ilman mitään tarjousta, authorization code -kulun kautta. Molemmat kulut päätyvät samaan pisteeseen: walletilla on käyttöoikeustoken, jota se voi käyttää credentialin pyytämiseen.

Pre-authorized code -kulku

1. Myöntäjä

Tuntee haltijan jo ja antaa Credential Offer -tarjouksen, jossa on pre-authorized_code

2. Wallet

Lunastaa koodin token-päätepisteessä, valinnaisesti transaktiokoodilla

3. Wallet

Pyytää credentialia todistaen hallitsevansa avainta

Authorization code -kulku

1. Wallet

Skannaa Credential Offer -tarjouksen, jossa mainitaan authorization_code-grant, tai aloittaa kulun itse ilman tarjousta

2. Valtuutuspalvelin

Vie haltijan kirjautumisen ja suostumuksen läpi ja myöntää sitten koodin

3. Wallet

Vaihtaa koodin tokeniin ja pyytää sitten credentialia

Credential-tarjouksen koko elinkaari

Spesifikaatio ei määrittele nimettyjä tiloja, mutta myöntäjän käynnistämä kulku, jossa credential myönnetään heti, on helpoin seurata alla olevan sekvenssin tapaan. Jokainen vaihe voi epäonnistua omalla tavallaan, ja walletin toteutuksen on käsiteltävä nämä polut, ei vain onnistunutta reittiä.

Tarjous luotu
QR-koodi tai linkki avaa walletin
Tarjous vastaanotettu
grant lunastettu
Token saatu
nonce ja hallinnan todistus
Credentialia pyydetty
credential luotu
Credential myönnetty
wallet validoi ja tallentaa
Credential hyväksytty
Missä kohtaa se voi epäonnistua, vaiheiden järjestyksessä:
Koodi vanhentui ennen lunastusta
Token-pyyntö evätty
Credential-pyyntö hylätty
Credentialia ei tallennettu

Esimerkki: katsastustodistus kuljetuskalustolle

Ajoneuvojen katsastuslaitos myöntää katsastustodistuksen kuljetusyrityksen yrityswalletiin rutiinikatsastuksen jälkeen. Katsastaja on jo todentanut kalustopäällikön katsastuspisteessä, joten myöntäjä käyttää pre-authorized code -kulkua. Alla olevat vaiheet seuraavat tätä yksittäistä myöntämistä tarjouksesta hyväksyttyyn credentialiin.

Esimerkki näyttää peruspiirteisen OpenID4VCI:n. Korkean varmuuden käyttöönotot, kuten EUDI Wallet, noudattavat tämän lisäksi HAIP-profiilia, joka lisää DPoP-sidottuja käyttöoikeustokeneita, wallet attestationin token-päätepisteessä ja key attestationin credential-avaimille. Ne on jätetty tästä pois, jotta jokainen vaihe pysyy luettavana.

1. Credential offer

Katsastuslaitoksen päätelaite näyttää QR-koodin. Se sisältää URI:n, joka alkaa openid-credential-offer:// ja kantaa alla olevaa tarjousta, URL-koodattuna credential_offer-parametrissa, tai credential_offer_uri-arvon, josta wallet hakee sen. Wallet skannaa sen ja lukee, mikä credential on tarjolla ja miten se hankitaan.

Myöntäjä

Näyttää QR-koodin, jossa on Credential Offer

Nimeää credential-konfiguraation ja pre-authorized_code-grantin

{
  "credential_issuer": "https://issuer.fleetinspect.example",
  "credential_configuration_ids": ["roadworthiness_certificate"],
  "grants": {
    "urn:ietf:params:oauth:grant-type:pre-authorized_code": {
      "pre-authorized_code": "fi-8f2c0b3a",
      "tx_code": {
        "length": 6,
        "input_mode": "numeric",
        "description": "Enter the code sent to your phone by text message"
      }
    }
  }
}

2. Myöntäjän metatietojen haku

Ennen kuin wallet pyytää mitään, se hakee myöntäjän metatiedot selvittääkseen, mitä roadworthiness_certificate sisältää ja mitä päätepisteitä sen tulee kutsua. Metatiedot eivät listaa erillisiä valtuutuspalvelimia, joten myöntäjä on oma valtuutuspalvelimensa, ja wallet lukee token-päätepisteen kyseisen palvelimen metatiedoista.

Wallet

GET /.well-known/openid-credential-issuer

Selvittää credential-muodon, väitteet ja hyväksytyt proof-tyypit sekä nonce-, credential-, deferred- ja notification-päätepisteet

Credentialin myöntäjän metatiedot (ote)

{
  "credential_issuer": "https://issuer.fleetinspect.example",
  "nonce_endpoint": "https://issuer.fleetinspect.example/nonce",
  "credential_endpoint": "https://issuer.fleetinspect.example/credential",
  "deferred_credential_endpoint": "https://issuer.fleetinspect.example/deferred",
  "notification_endpoint": "https://issuer.fleetinspect.example/notify",
  "credential_configurations_supported": {
    "roadworthiness_certificate": {
      "format": "dc+sd-jwt",
      "vct": "https://fleetinspect.example/vct/roadworthiness",
      "cryptographic_binding_methods_supported": ["jwk"],
      "credential_signing_alg_values_supported": ["ES256"],
      "proof_types_supported": {
        "jwt": { "proof_signing_alg_values_supported": ["ES256"] }
      },
      "credential_metadata": {
        "claims": [
          { "path": ["vehicle_registration"] },
          { "path": ["inspection_result"] },
          { "path": ["valid_until"] }
        ]
      }
    }
  }
}

Valtuutuspalvelimen metatiedot (ote), osoitteesta /.well-known/oauth-authorization-server

{
  "issuer": "https://issuer.fleetinspect.example",
  "token_endpoint": "https://issuer.fleetinspect.example/token",
  "pre-authorized_grant_anonymous_access_supported": true
}

3. Token-pyyntö

Wallet lunastaa pre-authorized coden token-päätepisteessä yhdessä transaktiokoodin kanssa, jonka katsastuslaitos lähetti kalustopäällikön puhelimeen. Koodin lähettäminen toista kanavaa pitkin tarkoittaa, että joku, joka kuvaa QR-koodin olan yli, ei silti pysty lunastamaan sitä.

Wallet

POST /token

Lähettää pre-authorized_code- ja tx_code-arvot, saa käyttöoikeustokenin, joka rajautuu tähän tarjoukseen

POST /token HTTP/1.1
Host: issuer.fleetinspect.example
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:pre-authorized_code
&pre-authorized_code=fi-8f2c0b3a
&tx_code=482913

Vastaus

{
  "access_token": "fi-at-3d91e0",
  "token_type": "Bearer",
  "expires_in": 86400
}

4. Hallinnan todistus

Koska metatiedot listaavat nonce_endpoint-päätepisteen, wallet hakee sieltä ensin tuoreen c_nonce-arvon. Sitten se todistaa hallitsevansa yksityistä avainta, johon credential sidotaan, allekirjoittamalla proof JWT:n myöntäjän tunnisteen ja tämän c_nonce-arvon yli.

Wallet

POST /nonce, allekirjoittaa sitten proof JWT:n avaimella, johon credential sidotaan

Sitoo credentialin tähän avaimeen, ei pelkästään käyttöoikeustokenin haltijaan

POST /nonce HTTP/1.1
Host: issuer.fleetinspect.example

Vastaus

{
  "c_nonce": "fi-nonce-77aa"
}

Wallet rakentaa nyt proof JWT:n kahdesta JSON-objektista, headerista ja payloadista, ja allekirjoittaa ne yksityisellä avaimella, johon credential sidotaan.

Header: mikä tämä JWT on ja mikä avain sen allekirjoitti

{
  "typ": "openid4vci-proof+jwt",
  "alg": "ES256",
  "jwk": { "kty": "EC", "crv": "P-256", "x": "...", "y": "..." }
}
  • typ: merkitsee tämän OpenID4VCI key proofiksi, jotta sitä ei sekoiteta muunlaiseen JWT:hen
  • alg: allekirjoitusalgoritmi, jonka myöntäjä listasi proof_signing_alg_values_supported-arvossa
  • jwk: julkinen avain, johon credential sidotaan; myöntäjä tarkistaa allekirjoituksen sitä vasten

Payload: kenelle proof on tarkoitettu ja milloin se tehtiin

{
  "aud": "https://issuer.fleetinspect.example",
  "iat": 1789376400,
  "nonce": "fi-nonce-77aa"
}
  • aud: myöntäjän tunniste, jotta proofia ei voi toistaa toisessa myöntäjässä
  • iat: hetki, jolloin proof luotiin, sekunteina vuodesta 1970
  • nonce: nonce-päätepisteestä saatu c_nonce, joka osoittaa proofin olevan tuore

Allekirjoitettu tulos

Header ja payload koodataan kumpikin base64url-muotoon ja yhdistetään pisteellä. Wallet allekirjoittaa tämän merkkijonon yksityisellä avaimellaan ja liittää base64url-koodatun allekirjoituksen toisen pisteen jälkeen. Syntyvä merkkijono on proof JWT, jonka wallet lähettää credential-pyynnössä vaiheessa 5.

base64url(header) . base64url(payload) . base64url(signature)

eyJ0eXAiOiJvcGVuaWQ0dmNpLXByb29mK2p3dCIs...
  .eyJhdWQiOiJodHRwczovL2lzc3Vlci5mbGVldGluc3BlY3QuZXhhbXBsZSIs...
  .<ES256 signature>

5. Credential-pyyntö

Wallet kutsuu credential-päätepistettä käyttöoikeustokenilla ja proofilla, ja myöntäjä luo ja palauttaa allekirjoitetun credentialin.

Wallet

POST /credential

Lähettää käyttöoikeustokenin, konfiguraatio-id:n ja proof JWT:n, saa allekirjoitetun credentialin ja notification_id:n

POST /credential HTTP/1.1
Host: issuer.fleetinspect.example
Content-Type: application/json
Authorization: Bearer fi-at-3d91e0

{
  "credential_configuration_id": "roadworthiness_certificate",
  "proofs": {
    "jwt": ["<proof JWT from step 4>"]
  }
}

Vastaus

{
  "credentials": [
    { "credential": "<issuer-signed SD-JWT VC>" }
  ],
  "notification_id": "fi-notif-9012"
}

Koko kulku yhdellä silmäyksellä

Tämä sekvenssikaavio kokoaa yhteen esimerkin viisi vaihetta, tarjouksesta ilmoitukseen. Yhtenäiset nuolet ovat pyyntöjä, katkoviivanuolet vastauksia, ja pisteviivanuoli kuvaa transaktiokoodia, joka kulkee protokollan ulkopuolella tekstiviestillä.

Wallet

Kuljetusyrityksen yrityswallet

Valtuutuspalvelin

Tässä esimerkissä myöntäjä ajaa sitä itse

Credentialin myöntäjä

Ajoneuvojen katsastuslaitos

  1. Credentialin myöntäjä kohteeseen Wallet: Credential Offer, esitetty QR-koodina
  2. Credentialin myöntäjä kohteeseen Wallet: tx_code, lähetetty tekstiviestillä kalustopäällikön puhelimeen
  3. Wallet kohteeseen Credentialin myöntäjä: GET /.well-known/openid-credential-issuer
  4. Credentialin myöntäjä kohteeseen Wallet: credentialin myöntäjän metatiedot
  5. Wallet kohteeseen Valtuutuspalvelin: GET /.well-known/oauth-authorization-server
  6. Valtuutuspalvelin kohteeseen Wallet: valtuutuspalvelimen metatiedot
  7. Wallet kohteeseen Valtuutuspalvelin: POST /token: pre-authorized_code, tx_code
  8. Valtuutuspalvelin kohteeseen Wallet: access_token
  9. Wallet kohteeseen Credentialin myöntäjä: POST /nonce
  10. Credentialin myöntäjä kohteeseen Wallet: c_nonce
  11. Wallet: allekirjoittaa proof JWT:n
  12. Wallet kohteeseen Credentialin myöntäjä: POST /credential: käyttöoikeustoken, proofit
  13. Credentialin myöntäjä kohteeseen Wallet: credentials, notification_id
  14. Wallet: validoi ja tallentaa
  15. Wallet kohteeseen Credentialin myöntäjä: POST /notify: credential_accepted
  16. Credentialin myöntäjä kohteeseen Wallet: 204 No Content

Kun credential ei ole vielä valmis: viivästetty myöntäminen

Yllä oleva esimerkki olettaa, että katsastustulos on jo lopullinen. Jos katsastuslaitoksen sen sijaan täytyy eskaloida rajatapaus vanhemmalle katsastajalle, credential-päätepiste ei voi palauttaa credentialia heti, joten se viivästää myöntämistä.

Välitön myöntäminen

Credential-päätepiste palauttaa allekirjoitetun credentialin samassa vastauksessa kuin pyyntö.

Viivästetty myöntäminen

Credential-päätepiste vastaa koodilla HTTP 202 sekä transaction_id- ja interval-arvolla. Wallet kysyy deferred credential -päätepisteeltä kyseisellä id:llä, odottaen vähintään interval sekuntia pyyntöjen välillä, kunnes credential on valmis.

transaction_idkysele deferred_credential_endpoint-päätepisteeltä

Viivästetty vastaus osoitteesta /credential

HTTP/1.1 202 Accepted
Content-Type: application/json

{
  "transaction_id": "fi-tx-55c2",
  "interval": 900
}

/deferred-osoitteen kysely, kunnes se on valmis

POST /deferred HTTP/1.1
Host: issuer.fleetinspect.example
Content-Type: application/json
Authorization: Bearer fi-at-3d91e0

{ "transaction_id": "fi-tx-55c2" }

// While the review is open: 202 with the same transaction_id and interval.
// Once approved: 200 with the credentials, optionally with a notification_id.
// If the review rejects the result: a credential_request_denied error.

Kehän sulkeminen: notification-päätepiste

Myöntämisen jälkeen wallet voi kertoa myöntäjälle, mitä credentialille tapahtui, käyttäen credential-vastauksesta saatua notification_id-arvoa. Walleteilla ei ole pakko lähettää näitä ilmoituksia, eikä toimitusta taata, joten myöntäjä ei voi tulkita puuttuvasta ilmoituksesta mitään.

Wallet

Lähettää tapahtuman myöntäjän notification_endpoint-päätepisteeseen vastaanotetulle notification_id:lle, joka kattaa jokaisen kyseisen vastauksen credentialin

credential_accepted

Tallennettu walletiin

credential_failure

Myöntäminen epäonnistui jostain muusta syystä, esimerkiksi koska credential ei validoitunut

credential_deleted

Myöntäminen epäonnistui haltijan toiminnan vuoksi, esimerkiksi koska hän kieltäytyi tallentamasta sitä

POST /notify HTTP/1.1
Host: issuer.fleetinspect.example
Content-Type: application/json
Authorization: Bearer fi-at-3d91e0

{
  "notification_id": "fi-notif-9012",
  "event": "credential_accepted"
}

Aiheeseen liittyvät termit

Usein kysytyt kysymykset

Mistä wallet tietää, mitä grant-tyyppiä käyttää?

Credential Offer nimeää grantin grants-objektissaan. authorization_code on läsnä, kun myöntäjä haluaa haltijan kirjautuvan osana kulkua. pre-authorized_code on läsnä, kun haltija oli jo todennettu kanavalla, jolla tarjous luotiin, esimerkiksi katsastajan toimesta katsastuspisteessä alla olevassa esimerkissä. Tarjous voi listata molemmat, jolloin wallet valitsee toisen. Jos tarjouksessa ei ole lainkaan grants-objektia, wallet tarkistaa valtuutuspalvelimen metatiedoista, mitä grant-tyyppejä tämä tukee.

Miksi wallet hakee myöntäjän metatiedot ennen kuin pyytää mitään?

Credential Offer nimeää vain credential_configuration_ids-arvot, myöntäjän URL:n ja grantit. Myöntäjän metatiedot, jotka tarjotaan well-known-polusta, kuvaavat kunkin konfiguraation: sen muodon, sen väitteet (claims) ja hyväksytyt proof-tyypit, sekä nonce-, credential-, deferred- ja notification-päätepisteet. Ne kertovat myös, mitä valtuutuspalvelinta käyttää, ja kyseisen palvelimen omat metatiedot antavat token-päätepisteen. Ilman molempia wallet ei tietäisi, miten rakentaa kelvollisia pyyntöjä tai mitä näyttää haltijalle ennen suostumusta.

Mitä hallinnan todistus oikeastaan todistaa?

Se todistaa, että credentialia pyytävä wallet hallitsee yksityistä avainta, johon credential sidotaan, eikä pelkästään että sillä on voimassa oleva käyttöoikeustoken. Wallet allekirjoittaa proof JWT:n myöntäjän tunnisteen ja myöntäjän nonce-päätepisteestä saadun tuoreen c_nonce-arvon yli käyttäen tätä avainta. Myöntäjä sisällyttää vastaavan julkisen avaimen credentialiin. Verifioija, joka vaatii avainsidontaa, pyytää haltijaa allekirjoittamaan uudelleen samalla avaimella esittäessään credentialin, jolloin kopioitu credential ilman avainta ei läpäise tätä tarkistusta.

Miksi myöntäjä viivästäisi myöntämistä sen sijaan, että palauttaisi credentialin heti?

Osaa myöntäjän ennen credentialin luomista tekemistä tarkistuksista ei voida suorittaa loppuun yhden HTTP-pyynnön sisällä, esimerkiksi manuaalista tarkastusta tai kutsua hitaaseen ulkoiseen rekisteriin. Viivästetty myöntäminen mahdollistaa sen, että credential-päätepiste vastaa heti transaction_id-arvolla yhteyden estämisen sijaan, ja wallet kysyy deferred-päätepisteeltä tällä id:llä, kunnes tarkistus valmistuu ja credential on valmis noudettavaksi.

Onko notification-päätepiste pakollinen myöntäjälle?

Ei. Se on myöntäjille valinnainen, eikä walleteillakaan ole pakko käyttää sitä. Kun molemmat tukevat sitä, myöntäjä saa tietää, mitä myöntämisen jälkeen tapahtui: credentialit tallennettiin (credential_accepted), haltija pysäytti myöntämisen, esimerkiksi kieltäytymällä tallentamasta niitä (credential_deleted), tai se epäonnistui jostain muusta syystä (credential_failure). Toimitusta ei taata, joten myöntäjän tulisi pitää ilmoitusta hyödyllisenä tietona, ei koskaan luotettavana tallenteena, eikä se voi päätellä mitään puuttuvasta ilmoituksesta.

Lähteet

  1. OpenID for Verifiable Credential Issuance 1.0
  2. OpenID4VC High Assurance Interoperability Profile 1.0
  3. EUDI Wallet Architecture and Reference Framework

Tämä sivu on informatiivinen eikä muodosta oikeudellista neuvontaa. Luotettavaa ohjeistusta varten ota yhteyttä suoraan OpenID Foundationiin ja Euroopan komissioon.

Keskustele kanssamme EUDI Wallet -integraatiosta