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 holder's interface that communicates with issuers and authorization servers to obtain credentials
  • Credential issuance service: Creates and issues credentials to the wallet
  • Authorization 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.

Request

curl -X 'GET' \
'https://issuer.example.org/issuance/oid4vci/credential-offer/{session_id}' \
-H 'accept: application/json'

Response

Header:

{
    "Content-type": "application/json"
}

Body:

{
  "grants": { // (3)!
    "urn:ietf:params:oauth:grant-type:pre-authorized_code": {
      "pre-authorized_code": "SCY7DQRYUWeOg3fNjK4AjQ"
    }
  },
  "credential_issuer": "https://issuer.example.org/", // (1)!
  "credential_configuration_ids": [ // (2)!
    "02336c44048962e0986523039dc4a2b1276c9a9ce0",
    "0228b80c917ed64925d936a6af4d514b92dbb9974f"
  ]
}
  1. Base URL for the issuer, used to fetch metadata from well-known endpoints.
  2. A list of IDs for specific credential configurations offered to the user.
  3. An object indicating to the wallet what grant types the issuers authorization server can process for this credential offer.

Wallet retrieves the metadata

Using the credential_issuer, the wallet request the issuer's 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.

Request

curl -X 'GET' \
'https://issuer.example.org/.well-known/openid-credential-issuer' \
-H 'accept: application/json'

Response

Header:

{
    "Content-type": "application/json"
}

Body:

{
  "credential_issuer": "https://issuer.example.org", // (1)!
  "credential_endpoint": "https://issuer.example.org/issuance/oid4vci/credential-request", // (2)!
  "nonce_endpoint": "https://issuer.example.org/issuance/oid4vci/nonce", // (3)!
  "authorization_servers": [ // (4)!
    "https://authorization-server.example.org"
  ],
  "credential_configurations_supported": { // (5)!
    "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": {}
        }
      }
    }
  }
}
  1. Base URL for the issuer, same as given in the credential offer.
  2. The endpoint used by the wallet to request credentials.
  3. The endpoint used by the wallet to fetch nonce's used during issuance.
  4. A list of authorization servers used to validate permissions.
  5. 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.

Wallet retrieves the authorization servers 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.

Request

curl -X 'GET' \
'https://authorization-server.example.org/.well-known/oauth-authorization-server' \
-H 'accept: application/json'

Response

Header:

{
    "Content-type": "application/json"
}

Body:

{
  "token_endpoint": "https://university-server.test1.partisia.dev/auth/token-endpoint", // (1)!
  "jwks_uri": "https://university-server.test1.partisia.dev/auth/.well-known/jwks" // (2)!
}
  1. The URL where the wallet can exchange the pre-authorized code for an access token.
  2. The URL where the authorization server exposes its public keys used for verification of tokens.

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.

Request

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'

Response

Header:

{
    "Content-type": "application/json"
}

Body:

{
  "access_token": "2YotnFZFEjr1zCsicMWpAA", // (1)!
  "token_type": "Bearer", // (2)!
  "expires_in": 300 // (3)!
}
  1. The token to include in the credential request.
  2. The type of token returned. This gives additional information to the wallet on how to use the token in the request.
  3. When the token expires in seconds.

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.

Request

curl -X 'POST' \
'http://issuer.example.org/issuance/oid4vci/nonce' \
-H 'accept: application/json'

Response

Header:

{
    "Content-type": "application/json"
}

Body:

{
  "c_nonce": "GjkK-hwL8MfvA07zavZY5A==" // (1)!
}
  1. A nonce to use later. e.g. within proofs

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 a private-public key pair, which will be used for holder binding within the issued credential. Note: The private key is used to sign the proof JWT.

A JWT proof consists of the following information in the header:

{
    "typ": "openid4vci-proof+jwt", //(1)!
    "alg": "ES256", //(2)!
    "kid": "did:jwk:eyJj..." //(3)!
}
  1. The type of proof openid4vci-proof+jwt
  2. A digital signature algorithm, such as ES256
  3. A key identifier, such as a did:jwk:...

The proof consists of the following information in the body:

{
    "nonce": "LarRGSbmUPYtRYO6BQ4yn8", //(1)!
    "aud": "https://credential-issuer.example.com", //(2)!
    "iat": 1701960444 //(3)!
}
  1. The nonce retrieved from the nonce endpoint
  2. The intended receiver of the proof. This is the issuer field of the credential offer.
  3. The time the proof was created. The credential issuance service only allows newly created proofs.

Request

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": "eyJ0eXAiOi..."
  }
}'

Response

Header:

{
    "Content-type": "application/json"
}

Body:

{
  "credentials": [ // (1)!
    {
      "credential": "eyJhbGciOiJF..." // (2)!
    }
  ]
}
  1. A list of objects each containing a credential
  2. The issued credential as a JWT

Credential in wallet

The wallet handles the received JWT according to wallet implementation, potentially prompting the user for input before proceeding.