Skip to content

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

issuance diagram

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:

{
    "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.