OpenID4VCI kredencialo išdavimas paaiškintas: nuo pasiūlymo iki priimto kredencialo
OpenID4VCI (OpenID for Verifiable Credential Issuance) apibrėžia, kaip piniginė užklausia ir gauna kredencialą iš išdavėjo. Vienas išdavimas vyksta per kelis atskirus žingsnius, kol piniginė iš tikrųjų gauna naudojamą kredencialą, ir kiekvienas žingsnis turi savo galimą nesėkmės būdą. Šiame puslapyje visas šis ciklas aprašomas išsamiai, pateikiant originalius praktinius pavyzdžius.
Du būdai pradėti: iš anksto autorizuotas kodas ir autorizacijos kodas
Išdavimas dažnai prasideda nuo išdavėjo atsiųsto kredencialo pasiūlymo, o jame nurodyta dotacija lemia, kaip piniginė gauna autorizaciją. Piniginė taip pat gali pati pradėti išdavimą be jokio pasiūlymo, naudodama autorizacijos kodo procesą. Abu procesai baigiasi ta pačia vieta: piniginė turi prieigos raktą, kurį gali naudoti kredencialui užklausti.
Iš anksto autorizuoto kodo procesas
1. Išdavėjas
Jau žino turėtoją, pateikia kredencialo pasiūlymą su pre-authorized_code
2. Piniginė
Iškeičia kodą prieigos rakto galiniame taške, pasirinktinai su operacijos kodu
3. Piniginė
Užklausia kredencialo, pateikdamas savo rakto turėjimo įrodymą
Autorizacijos kodo procesas
1. Piniginė
Nuskaito kredencialo pasiūlymą, nurodantį authorization_code dotaciją, arba pati pradeda procesą be pasiūlymo
2. Autorizacijos serveris
Nukreipia turėtoją per prisijungimą ir sutikimą, tada išduoda kodą
3. Piniginė
Iškeičia kodą į prieigos raktą, tada užklausia kredencialo
Visas kredencialo pasiūlymo gyvavimo ciklas
Specifikacija neapibrėžia pavadintų būsenų, tačiau išdavėjo inicijuotą procesą, kuriame kredencialas išduodamas iš karto, lengviausia sekti taip, kaip parodyta toliau pateiktoje sekoje. Kiekvienas žingsnis gali nepavykti savaip, ir piniginės diegimas turi apdoroti tuos atvejus, ne tik sėkmingą scenarijų.
Praktinis pavyzdys: krovinių parko techninės apžiūros pažymėjimas
Transporto priemonių apžiūros įstaiga po įprastos apžiūros išduoda techninės apžiūros pažymėjimą krovinių vežimo įmonės verslo piniginei. Apžiūrėtojas jau autentifikavo parko vadovą apžiūros punkte, todėl išdavėjas naudoja iš anksto autorizuoto kodo procesą. Toliau aprašyti žingsniai seka šį vieną išdavimą nuo pasiūlymo iki priimto kredencialo.
Šis pavyzdys rodo bazinį OpenID4VCI. Aukšto patikimumo diegimai, tokie kaip ES skaitmeninė piniginė (EUDI Wallet), virš jo taiko HAIP profilį, kuris prideda su DPoP susietus prieigos raktus, piniginės atestaciją prieigos rakto galiniame taške ir rakto atestaciją kredencialo raktams. Čia jie praleisti, kad kiekvienas žingsnis liktų aiškus.
1. Kredencialo pasiūlymas
Apžiūros įstaigos terminale rodomas QR kodas. Jame yra URI, prasidedantis openid-credential-offer://, kuris perduoda toliau pateiktą pasiūlymą, URL užkoduotą credential_offer parametre, arba credential_offer_uri, iš kurio piniginė jį gauna. Piniginė nuskaito kodą ir sužino, koks kredencialas siūlomas ir kaip jį gauti.
Išdavėjas
Rodomas QR kodas su kredencialo pasiūlymu
Nurodoma kredencialo konfigūracija ir pre-authorized_code dotacija
{
"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. Išdavėjo metaduomenų paieška
Prieš pateikdama bet kokią užklausą, piniginė gauna išdavėjo metaduomenis, kad sužinotų, ką apima roadworthiness_certificate ir kokius galinius taškus reikia kviesti. Metaduomenyse nenurodyti atskiri autorizacijos serveriai, todėl išdavėjas yra pats savo autorizacijos serveris, o piniginė prieigos rakto galinį tašką nuskaito iš to serverio metaduomenų.
Piniginė
GET /.well-known/openid-credential-issuer
Sužinomas kredencialo formatas, teiginiai ir priimami įrodymo tipai, taip pat nonce, credential, deferred ir notification galiniai taškai
Kredencialo išdavėjo metaduomenys (ištrauka)
{
"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"] }
]
}
}
}
}Autorizacijos serverio metaduomenys (ištrauka) iš /.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. Prieigos rakto užklausa
Piniginė iškeičia iš anksto autorizuotą kodą prieigos rakto galiniame taške kartu su operacijos kodu, kurį apžiūros įstaiga išsiuntė parko vadovo telefonu. Šio kodo siuntimas antru kanalu reiškia, kad asmuo, nufotografavęs QR kodą per petį, jo vis tiek negalės iškeisti.
Piniginė
POST /token
Siunčiami pre-authorized_code ir tx_code, gaunamas šiam pasiūlymui skirtas prieigos raktas
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
Atsakymas
{
"access_token": "fi-at-3d91e0",
"token_type": "Bearer",
"expires_in": 86400
}4. Rakto turėjimo įrodymas
Kadangi metaduomenyse nurodytas nonce_endpoint, piniginė pirmiausia iš ten gauna šviežią c_nonce. Tada ji įrodo, kad turi privatų raktą, prie kurio kredencialas bus priskirtas, pasirašydama proof JWT su išdavėjo identifikatoriumi ir tuo c_nonce.
Piniginė
POST /nonce, tada pasirašomas proof JWT raktu, prie kurio bus priskirtas kredencialas
Kredencialas susiejamas su tuo raktu, o ne vien su tuo, kas turi prieigos raktą
POST /nonce HTTP/1.1 Host: issuer.fleetinspect.example
Atsakymas
{
"c_nonce": "fi-nonce-77aa"
}Dabar piniginė sukuria proof JWT iš dviejų JSON objektų, antraštės ir naudingosios apkrovos, ir pasirašo juos privačiu raktu, prie kurio bus priskirtas kredencialas.
Antraštė: kas yra šis JWT ir kuriuo raktu jis pasirašytas
{
"typ": "openid4vci-proof+jwt",
"alg": "ES256",
"jwk": { "kty": "EC", "crv": "P-256", "x": "...", "y": "..." }
}typ: žymi, kad tai OpenID4VCI rakto įrodymas, todėl jo negalima supainioti su jokiu kitu JWT tipualg: pasirašymo algoritmas, vienas iš tų, kuriuos išdavėjas nurodė proof_signing_alg_values_supported sąrašejwk: viešasis raktas, prie kurio bus priskirtas kredencialas; išdavėjas pagal jį tikrina parašą
Naudingoji apkrova: kam skirtas įrodymas ir kada jis sukurtas
{
"aud": "https://issuer.fleetinspect.example",
"iat": 1789376400,
"nonce": "fi-nonce-77aa"
}aud: išdavėjo identifikatorius, kad įrodymo nebūtų galima pakartotinai panaudoti pas kitą išdavėjąiat: įrodymo sukūrimo laikas, sekundėmis nuo 1970 metųnonce: c_nonce iš nonce endpoint, rodantis, kad įrodymas yra šviežias
Pasirašytas rezultatas
Antraštė ir naudingoji apkrova kiekviena užkoduojama base64url formatu ir sujungiamos tašku. Piniginė pasirašo šią eilutę savo privačiu raktu ir po antro taško prideda base64url užkoduotą parašą. Gauta eilutė yra proof JWT, kurį piniginė siunčia kredencialo užklausoje 5 žingsnyje.
base64url(header) . base64url(payload) . base64url(signature) eyJ0eXAiOiJvcGVuaWQ0dmNpLXByb29mK2p3dCIs... .eyJhdWQiOiJodHRwczovL2lzc3Vlci5mbGVldGluc3BlY3QuZXhhbXBsZSIs... .<ES256 signature>
5. Kredencialo užklausa
Piniginė kreipiasi į kredencialo galinį tašką su prieigos raktu ir įrodymu, o išdavėjas sukuria ir grąžina pasirašytą kredencialą.
Piniginė
POST /credential
Siunčiami prieigos raktas, konfigūracijos id ir proof JWT, gaunamas pasirašytas kredencialas ir notification_id
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>"]
}
}Atsakymas
{
"credentials": [
{ "credential": "<issuer-signed SD-JWT VC>" }
],
"notification_id": "fi-notif-9012"
}Visas procesas vienu žvilgsniu
Ši sekų diagrama sujungia penkis darbinio pavyzdžio žingsnius, nuo pasiūlymo iki pranešimo. Ištisinės rodyklės yra užklausos, brūkšninės rodyklės - atsakymai, o taškuota rodyklė - operacijos kodas, kuris keliauja už protokolo ribų SMS žinute.
Piniginė
Krovinių vežimo įmonės verslo piniginė
Autorizacijos serveris
Šiame pavyzdyje valdomas paties išdavėjo
Kredencialo išdavėjas
Transporto priemonių apžiūros įstaiga
- Kredencialo išdavėjas iki Piniginė: Kredencialo pasiūlymas, rodomas kaip QR kodas
- Kredencialo išdavėjas iki Piniginė: tx_code, siunčiamas parko vadovo telefonu SMS žinute
- Piniginė iki Kredencialo išdavėjas: GET /.well-known/openid-credential-issuer
- Kredencialo išdavėjas iki Piniginė: kredencialo išdavėjo metaduomenys
- Piniginė iki Autorizacijos serveris: GET /.well-known/oauth-authorization-server
- Autorizacijos serveris iki Piniginė: autorizacijos serverio metaduomenys
- Piniginė iki Autorizacijos serveris: POST /token: pre-authorized_code, tx_code
- Autorizacijos serveris iki Piniginė: access_token
- Piniginė iki Kredencialo išdavėjas: POST /nonce
- Kredencialo išdavėjas iki Piniginė: c_nonce
- Piniginė: pasirašo proof JWT
- Piniginė iki Kredencialo išdavėjas: POST /credential: prieigos raktas, įrodymai
- Kredencialo išdavėjas iki Piniginė: credentials, notification_id
- Piniginė: patvirtina ir saugo
- Piniginė iki Kredencialo išdavėjas: POST /notify: credential_accepted
- Kredencialo išdavėjas iki Piniginė: 204 No Content
Kai kredencialas dar neparuoštas: atidėtas išdavimas
Aukščiau pateiktame pavyzdyje daroma prielaida, kad apžiūros rezultatas jau galutinis. Jei vietoj to apžiūros įstaigai reikia perduoti ribinį rezultatą vyresniajam apžiūrėtojui, kredencialo galinis taškas negali iš karto grąžinti kredencialo, todėl jis atideda išdavimą.
Tiesioginis išdavimas
Kredencialo galinis taškas grąžina pasirašytą kredencialą tame pačiame atsakyme kaip ir užklausa.
Atidėtas išdavimas
Kredencialo galinis taškas vietoj to atsako HTTP 202 kodu, transaction_id ir intervalu. Piniginė apklausia atidėto kredencialo galinį tašką su tuo id, laukdama bent interval sekundžių tarp užklausų, kol kredencialas bus paruoštas.
Atidėtas atsakymas iš /credential
HTTP/1.1 202 Accepted
Content-Type: application/json
{
"transaction_id": "fi-tx-55c2",
"interval": 900
}Apklausiamas /deferred, kol jis bus paruoštas
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.Ciklo užbaigimas: pranešimų galinis taškas
Po išdavimo piniginė gali pranešti išdavėjui, kas nutiko su kredencialu, naudodama notification_id iš kredencialo atsakymo. Piniginėms nebūtina siųsti šių pranešimų, o pristatymas negarantuojamas, todėl išdavėjas negali laikyti, kad trūkstamas pranešimas ką nors reiškia.
Piniginė
Išsiunčia įvykį į išdavėjo notification_endpoint apie gautą notification_id, kuris apima visus tame atsakyme buvusius kredencialus
Išsaugota piniginėje
Išdavimas nepavyko dėl kitos priežasties, pavyzdžiui, kredencialas nepraėjo patvirtinimo
Išdavimas nepavyko dėl turėtojo, pavyzdžiui, jis atsisakė jį saugoti
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"
}Susijusios sąvokos
Dažniausiai užduodami klausimai
Kaip piniginė žino, kokį dotacijos tipą naudoti?
Kredencialo pasiūlymas nurodo dotaciją savo grants objekte. authorization_code yra pateikiamas, kai išdavėjas nori, kad turėtojas prisijungtų proceso metu. pre-authorized_code yra pateikiamas, kai turėtojas jau buvo autentifikuotas tame kanale, kuriame pasiūlymas buvo sukurtas, pavyzdžiui, apžiūrėtojo darbinio pavyzdžio apžiūros punkte, aprašytame toliau. Pasiūlyme gali būti nurodyti abu variantai, ir tuomet piniginė pasirenka vieną iš jų. Jei pasiūlyme visai nėra grants objekto, piniginė patikrina, kokius dotacijos tipus palaiko autorizacijos serveris, jo metaduomenyse.
Kodėl piniginė gauna išdavėjo metaduomenis prieš pateikdama bet kokią užklausą?
Kredencialo pasiūlyme nurodyti tik credential_configuration_ids, išdavėjo URL ir grants. Išdavėjo metaduomenys, pateikiami iš gerai žinomo (well-known) adreso, aprašo kiekvieną konfigūraciją: jos formatą, teiginius (claims) ir priimamus įrodymo tipus, taip pat nonce, credential, deferred ir notification galinius taškus. Juose taip pat nurodyta, kurį autorizacijos serverį naudoti, o to serverio paties metaduomenys pateikia prieigos rakto galinį tašką. Neturėdama abiejų, piniginė nežinotų, kaip sukurti tinkamas užklausas ar ką rodyti turėtojui prieš jam sutinkant.
Ką iš tikrųjų įrodo rakto turėjimo įrodymas (proof of possession)?
Jis įrodo, kad kredencialo prašanti piniginė turi privatų raktą, prie kurio kredencialas bus priskirtas, o ne tik tai, kad ji turi galiojantį prieigos raktą. Piniginė pasirašo proof JWT su tuo raktu, apimdama išdavėjo identifikatorių ir šviežią c_nonce iš išdavėjo nonce endpoint. Išdavėjas įterpia atitinkamą viešąjį raktą į kredencialą. Tikrintojas, kuriam reikalingas rakto susiejimas, prašo turėtojo vėl pasirašyti tuo pačiu raktu pateikiant kredencialą, todėl nukopijuotas kredencialas be rakto tokio patikrinimo neatlaiko.
Kodėl išdavėjas gali atidėti išdavimą, užuot iš karto grąžinęs kredencialą?
Kai kurie patikrinimai, kuriuos išdavėjas atlieka prieš sukurdamas kredencialą, negali būti užbaigti per vieną HTTP užklausą, pavyzdžiui, rankinė peržiūra arba kreipimasis į lėtą išorinį registrą. Atidėtas išdavimas leidžia kredencialo galiniam taškui iš karto atsakyti su transaction_id, o ne blokuoti ryšį, ir piniginė apklausia atidėto galinio taško su tuo id, kol patikrinimas bus baigtas ir kredencialas bus paruoštas atsiimti.
Ar pranešimų galinis taškas (notification endpoint) privalomas išdavėjui įdiegti?
Ne. Išdavėjams tai neprivaloma, o ir piniginėms nebūtina jo naudoti. Kai abu jį palaiko, išdavėjas sužino, kas nutiko po išdavimo: kredencialai buvo išsaugoti (credential_accepted), turėtojas nutraukė išdavimą, pavyzdžiui, atsisakė jį saugoti (credential_deleted), arba jis nepavyko dėl kitos priežasties (credential_failure). Pristatymas negarantuojamas, todėl išdavėjas turėtų vertinti pranešimą kaip naudingą informaciją, o ne kaip patikimą įrašą, ir negali daryti jokių išvadų iš to, kad pranešimo negavo.
Šaltiniai
Šis puslapis yra informacinio pobūdžio ir nėra teisinė konsultacija. Dėl oficialių gairių kreipkitės tiesiogiai į OpenID Foundation ir Europos Komisiją.