Issuance
This article provides a detailed overview of the OID4VCI protocol steps managed by Partisia's credential issuance service in the Pre-authorized flow. All these steps are entirely carried out by Partisia's credential issuance service, relieving the issuer of these tasks.
The following explanation, thus, expands on step number 8 in the diagram involving 3 roles:
- Wallet: The holders interface that communicates with issuers and auth servers to obtain credentials
- Credential issuance service: Creates and issues credentials to the wallet
- Auth server: Issues access tokens which are used to ensure credentials are only issued to authenticated holders
Note
In the following examples only fields required to understand the flow of information are included.
Wallet retrieves the credential offer
At this point in the flow, the wallet has received the credential offer URI from your application. At which point the wallet retrieves the credential offer by calling the credential issuance service.
curl -X 'GET' \
'https://issuer.example.org/issuance/oid4vci/credential-offer/{session_id}' \
-H 'accept: application/json'
Credential issuance service returns the credential offer
The credential issuance service responds to the wallet's request by sending the following key components:
- Credential Issuer: Base url for the issuer, used to fetch meta-information from well-known endpoints.
- Credential Configuration IDs: A list of IDs for specific credential configurations offered to the user
- Grants: An object indicating to the wallet what grant types the issuers authorization server can process for this credential offer.
For example, the response might look like this:
Header:
{
"Content-type": "application/json"
}
Body:
{
"grants": {
"urn:ietf:params:oauth:grant-type:pre-authorized_code": {
"pre-authorized_code": "SCY7DQRYUWeOg3fNjK4AjQ"
}
},
"credential_issuer": "https://issuer.example.org/",
"credential_configuration_ids": [
"02336c44048962e0986523039dc4a2b1276c9a9ce0",
"0228b80c917ed64925d936a6af4d514b92dbb9974f"
]
}
Wallet retrieves the meta data
Using the credential_issuer
, the wallet request the issuers metadata on the .well-known endpoint
defined
in Section 11.2.2 of OID4VCI.
This step provides the wallet with information required to proceed with the credential request.
curl -X 'GET' \
'https://issuer.example.org/.well-known/openid-credential-issuer' \
-H 'accept: application/json'
Credential issuance service returns the meta data
The credential issuance service responds to the wallet's request by sending the following key components:
- Credential Issuer: Base url for the issuer, same as given in the credential offer.
- Credential Endpoint: The endpoint used by the wallet to request credentials.
- Nonce Endpoint: The endpoint the wallet must use to fetch a nonce used to prove possession of private keys for holder binding.
- Authorization Servers: A list of authorization servers used to validate permissions.
- Credential Configurations Supported: An object containing all credential configurations supported by the issuer. The Credential Configurations IDs retrieved in the credential offer is a subset of those in this list.
For example, the response might look like this:
Header:
{
"Content-type": "application/json"
}
Body:
{
"credential_issuer": "https://issuer.example.org",
"credential_endpoint": "https://issuer.example.org/issuance/oid4vci/credential-request",
"nonce_endpoint": "https://issuer.example.org/issuance/oid4vci/nonce",
"authorization_servers": ["https://authorization-server.example.org"],
"credential_configurations_supported": {
"02336c44048962e0986523039dc4a2b1276c9a9ce0": {
"format": "jwt_vc_json-ld",
"credential_definition": {
"type": ["VerifiableCredential", "StudyID"],
"@context": ["https://www.w3.org/ns/credentials/v2"],
"credentialSubject": {
"first_name": {},
"last_name": {},
"student_id": {},
"portrait": {},
"university": {}
}
}
}
}
}
Wallet retrieves the authorization server metadata
Using the authorization_servers
, the wallet requests the metadata on the .well-known endpoint
defined
in RFC8414
for the relevant authorization server.
This step provides the wallet with the endpoint where the pre-authorized token can be exchanged for
a traditional OAUTH2.0 access token.
curl -X 'GET' \
'https://authorization-server.example.org/.well-known/oauth-authorization-server' \
-H 'accept: application/json'
Authorization server returns the metadata
The authorization server response to the wallet's request by sending the following key components:
- Token Endpoint: The url where the wallet can exchange the pre-authorized code for an access token.
For example, the response might look like this:
Header:
{
"Content-type": "application/json"
}
Body:
{
"token_endpoint": "https://university-server.test1.partisia.dev/auth/token-endpoint"
}
Wallet retrieves the access token
Using the grant
from the credential offer and the token_endpoint
of the authorization server
metadata, the wallet requests an OAUTH2.0 access token to be used in the request of a credential.
curl -X 'POST' \
'https://authorization-server.example.org/.well-known/oauth-authorization-server' \
-H 'accept: application/json' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Apre-authorized_code&pre-authorized_code=SplxlOBeZQQYbYS6WxSbIA'
Authorization server returns the access token
The authorization server response to the wallet's request by sending the following key components:
- Access Token: The token to include in the credential request.
- Token Type: The type of token returned. This gives additional information to the wallet on how to use the token in the request.
- Expires in: When the token expires in ms.
For example, the response might look like this:
Header:
{
"Content-type": "application/json"
}
Body:
{
"access_token": "2YotnFZFEjr1zCsicMWpAA",
"token_type": "Bearer",
"expires_in": 300
}
Wallet retrieves a nonce
Using the nonce_endpoint
from the metadata of the credential issuance service, the wallet requests
a nonce to be used in the proof of possession for private keys in the request for a credential.
curl -X 'POST' \
'http://issuer.example.org/issuance/oid4vci/nonce' \
-H 'accept: application/json' \
-d ''
Credential issuance service returns a nonce
The credential issuance service responds to the wallet's request by sending the following key components:
- c_nonce: The nonce to use later.
- Token Type: The type of token returned. This gives additional information to the wallet on how to use the token in the request.
For example, the response might look like this:
Header:
{
"Content-type": "application/json"
}
Body:
{
"c_nonce": "GjkK-hwL8MfvA07zavZY5A=="
}
Wallet retrieves the credentials
Using the credential_endpoint
from the metadata of the credential issuance service, the wallet
requests a credential by providing the following information:
- Credential Configuration ID: The ID of the credential configuration the holder wants to retrieve.
- Proof: A proof that shows that the owner possesses the private-public-key pair used to sign the JWT proof.
The proof consists of the following information in the header:
- typ: The type of proof
openid4vci-proof+jwt
- alg: A digital signature algorithm, such as
ES256
- kid: A key identifier, such as a
did:jwk:...
The proof consists of the following information in the body:
- nonce: The nonce retrieved from the nonce endpoint
- aud: The intended receiver of the proof. This is the
issuer
field of the credential offer. - iat: The time the proof was created. The credential issuance service only allows newly created proofs.
For example, the request might look like this:
curl -X 'POST' \
'http://issuer.example.org/issuance/oid4vci/credential-request' \
-H 'accept: application/json' \
-H 'Authorization: Bearer 2YotnFZFEjr1zCsicMWpAA' \
-H 'Content-Type: application/json' \
-d '{
"credential_configuration_id": "02336c44048962e0986523039dc4a2b1276c9a9ce0",
"proof": {
"proof_type": "jwt",
"jwt": "eyJ0eXAiOiJvcGVuaWQ0dmNpLXByb29mK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiblVXQW9BdjNYWml0aDhFN2kxOU9kYXhPTFlGT3dNLVoyRXVNMDJUaXJUNCIsInkiOiJIc2tIVThCalVpMVU5WHFpN1N3bWo4Z3dBS18weGtjRGpFV183MVNvc0VZIn19.eyJhdWQiOiJodHRwczovL2NyZWRlbnRpYWwtaXNzdWVyLmV4YW1wbGUuY29tIiwiaWF0IjoxNzAxOTYwNDQ0LCJub25jZSI6IkxhclJHU2JtVVBZdFJZTzZCUTR5bjgifQ.-a3EDsxClUB4O3LeDD5DVGEnNMT01FCQW4P6-2-BNBqc_Zxf0Qw4CWayLEpqkAomlkLb9zioZoipdP-jvh1WlA"
}
}'
Credential issuance services returns a credential
The credential issuance service responds to the wallet's request by sending the following key components:
- Credentials: A list of objects each containing a credential
- Credential: The issued credential
For example, the response might look like this:
Header:
{
"Content-type": "application/json"
}
Body:
{
"credentials": [
{
"credential": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL2V4YW1wbGVzL3YxIl0sImlkIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzM3MzIiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVW5pdmVyc2l0eURlZ3JlZUNyZWRlbnRpYWwiXSwiaXNzdWVyIjoiaHR0cHM6Ly9leGFtcGxlLmVkdS9pc3N1ZXJzLzU2NTA0OSIsImlzc3VhbmNlRGF0ZSI6IjIwMTAtMDEtMDFUMDA6MDA6MDBaIiwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmNzEyZWJjNmYxYzI3NmUxMmVjMjEiLCJkZWdyZWUiOnsidHlwZSI6IkJhY2hlbG9yRGVncmVlIiwibmFtZSI6IkJhY2hlbG9yIG9mIFNjaWVuY2UgYW5kIEFydHMifX19LCJpc3MiOiJodHRwczovL2V4YW1wbGUuZWR1L2lzc3VlcnMvNTY1MDQ5IiwibmJmIjoxMjYyMzA0MDAwLCJqdGkiOiJodHRwOi8vZXhhbXBsZS5lZHUvY3JlZGVudGlhbHMvMzczMiIsInN1YiI6ImRpZDpleGFtcGxlOmViZmViMWY3MTJlYmM2ZjFjMjc2ZTEyZWMyMSJ9.z5vgMTK1nfizNCg5N-niCOL3WUIAL7nXy-nGhDZYO_-PNGeE-0djCpWAMH8fD8eWSID5PfkPBYkx_dfLJnQ7NA"
}
]
}
User Confirmation in the Wallet
The wallet prompts the user to confirm their intent to proceed. The user must swipe to approve the received credential before it is stored in the wallet.