Praleisti ir pereiti prie pagrindinio turinio

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

Pasiūlymas sukurtas
QR kodas arba nuoroda atveria piniginę
Pasiūlymas gautas
dotacija iškeista
Prieigos raktas gautas
nonce ir rakto turėjimo įrodymas
Kredencialo užklausta
kredencialas sukuriamas
Kredencialas išduotas
piniginė patvirtina ir saugo
Kredencialas priimtas
Kur gali įvykti klaida, žingsnių vykdymo tvarka:
Kodo galiojimas baigėsi prieš jį iškeičiant
Prieigos rakto užklausa atmesta
Kredencialo užklausa atmesta
Kredencialas nesaugomas

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 tipu
  • alg: pasirašymo algoritmas, vienas iš tų, kuriuos išdavėjas nurodė proof_signing_alg_values_supported sąraše
  • jwk: 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

  1. Kredencialo išdavėjas iki Piniginė: Kredencialo pasiūlymas, rodomas kaip QR kodas
  2. Kredencialo išdavėjas iki Piniginė: tx_code, siunčiamas parko vadovo telefonu SMS žinute
  3. Piniginė iki Kredencialo išdavėjas: GET /.well-known/openid-credential-issuer
  4. Kredencialo išdavėjas iki Piniginė: kredencialo išdavėjo metaduomenys
  5. Piniginė iki Autorizacijos serveris: GET /.well-known/oauth-authorization-server
  6. Autorizacijos serveris iki Piniginė: autorizacijos serverio metaduomenys
  7. Piniginė iki Autorizacijos serveris: POST /token: pre-authorized_code, tx_code
  8. Autorizacijos serveris iki Piniginė: access_token
  9. Piniginė iki Kredencialo išdavėjas: POST /nonce
  10. Kredencialo išdavėjas iki Piniginė: c_nonce
  11. Piniginė: pasirašo proof JWT
  12. Piniginė iki Kredencialo išdavėjas: POST /credential: prieigos raktas, įrodymai
  13. Kredencialo išdavėjas iki Piniginė: credentials, notification_id
  14. Piniginė: patvirtina ir saugo
  15. Piniginė iki Kredencialo išdavėjas: POST /notify: credential_accepted
  16. 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.

transaction_idapklausti deferred_credential_endpoint

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

credential_accepted

Išsaugota piniginėje

credential_failure

Išdavimas nepavyko dėl kitos priežasties, pavyzdžiui, kredencialas nepraėjo patvirtinimo

credential_deleted

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

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

Šis puslapis yra informacinio pobūdžio ir nėra teisinė konsultacija. Dėl oficialių gairių kreipkitės tiesiogiai į OpenID Foundation ir Europos Komisiją.

Susisiekite dėl integracijos su ES skaitmenine pinigine (EUDI Wallet)