Skip to content

Commit

Permalink
feat: migrate issue endpoint to tapir (#516)
Browse files Browse the repository at this point in the history
* feat: migrate issue endpoint to tapir

* chore: add http error generation spec, remove recursive log print

* chore: remove subjectId from Create Issue Credential request

* chore: run scalafmt

* chore: remove issue api from old OAS and ref tapir generated

* chore: remove unused models in oas helpers

* chore: add integration tests to IssueController for httpErrorResponses

* chore: fix layer composition in test

* fix: fix test compilation and ensure test passes for incorrect subjectId

* chore: scalafmt in test scope
  • Loading branch information
davidpoltorak-io authored May 9, 2023
1 parent 8c8ad2a commit 9b1558f
Show file tree
Hide file tree
Showing 35 changed files with 1,666 additions and 585 deletions.
26 changes: 16 additions & 10 deletions docs/docusaurus/credentials/issue.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,9 @@ The protocol consists of the following main parts:
2. The Holder can then retrieve the offer using the [`/issue-credentials/records`](/agent-api/#tag/Issue-Credentials-Protocol/operation/getCredentialRecords) endpoint and accept the offer using the [`/issue-credentials/records/{recordId}/accept-offer`](/agent-api/#tag/Issue-Credentials-Protocol/operation/acceptCredentialOffer) endpoint.
3. The Issuer then uses the [`/issue-credentials/records/{recordId}/issue-credential`](/agent-api/#tag/Issue-Credentials-Protocol/operation/issueCredential) endpoint to issue the credential, which gets sent to the Holder via [DIDComm](/docs/concepts/glossary#didcomm). The Holder receives the credential, and the protocol is complete.

The schema identifier defines the structure and the credential type issued,
while the claims provide specific information about the individual, such as their name or qualifications.
The claims provide specific information about the individual, such as their name or qualifications.

This protocol applies in various real-life scenarios, such as educational credentialing, employment verification, etc.
This protocol is applicable in various real-life scenarios, such as educational credentialing, employment verification, and more.
In these scenarios, the Issuer could be a school, an employer, etc., and the Holder could be a student or an employee.
The VCs issued during this protocol could represent a diploma, a certificate of employment, etc.

Expand Down Expand Up @@ -62,8 +61,15 @@ This section describes the Issuer role's available interactions with the PRISM A
To start the process, the issuer needs to create a credential offer.
To do this, make a `POST` request to the [`/issue-credentials/credential-offers`](/agent-api/#tag/Issue-Credentials-Protocol/operation/createCredentialOffer) endpoint with a JSON payload that includes the following information:

1. `schemaId`: This is an identifier for a schema, which defines the structure and format of the data in a verifiable credential. The schema identifier must be unique and typically a URL or a URN.
2. `claims`: are the data stored in a verifiable credential. Claims get expressed in a key-value format and must conform to the structure and format defined in the schema. Claims contain the data that the issuer attests to, such as name, address, date of birth, etc.
1. `claims`: The data stored in a verifiable credential. Claims get expressed in a key-value format. The claims contain the data that the issuer attests to, such as name, address, date of birth, and so on.
2. `issuingDID`: The DID referring to the issuer to issue this credential from
3. `connectionId`: The unique ID of the connection between the holder and the issuer to offer this credential over.

:::note

The issuingDID and connectionId properties come from completing the pre-requisite steps of listed above

:::

Once the request initiates, a new credential record for the issuer gets created with a unique ID. The state of this record is now `OfferPending`.

Expand All @@ -75,14 +81,14 @@ curl -X 'POST' \
-H 'Content-Type: application/json' \
-H "apiKey: $API_KEY" \
-d '{
"schemaId": "schema:1234",
"subjectId": "did:prism:subjectIdentifier",
"claims": {
"firstname": "Alice",
"lastname": "Wonderland",
"birthdate": "01/01/2000"
}
}'
},
"issuingDID": "did:prism:9f847f8bbb66c112f71d08ab39930d468ccbfe1e0e1d002be53d46c431212c26",
"connectionId": "9d075518-f97e-4f11-9d10-d7348a7a0fda"
}'
```

### Sending the Offer to the Holder
Expand Down Expand Up @@ -192,4 +198,4 @@ stateDiagram-v2

The following diagram shows the end-to-end flow for an issuer to issue a VC to a holder.

![](issue-flow.png)
![](issue-flow.png)
5 changes: 5 additions & 0 deletions infrastructure/shared/apisix/conf/apisix.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ routes:
plugins:
proxy-rewrite:
uri: "/connection-invitations"
- uri: /prism-agent/issue-credentials/*
upstream_id: 4
plugins:
proxy-rewrite:
regex_uri: ["^/prism-agent/issue-credentials/(.*)?", "/issue-credentials/$1"]
- uri: /didcomm
upstream_id: 3
plugins:
Expand Down
8 changes: 0 additions & 8 deletions prism-agent/service/api/http/pollux/parameters.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
components:
parameters:
issueCredentialRecordIdInPath:
in: path
name: recordId
required: true
description: The unique identifier of the issue credential record.
schema:
type: string
format: uuid
presentationRecordIdInPath:
in: path
name: recordId
Expand Down
124 changes: 0 additions & 124 deletions prism-agent/service/api/http/pollux/schemas.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -405,130 +405,6 @@ components:
items:
$ref: "#/components/schemas/VerificationPolicy"

# Issue Credential Protocol

IssueCredentialRecordBase:
required:
- claims
properties:
schemaId:
type: string
description: The unique identifier of the schema used for this credential offer.
subjectId:
type: string
description: The identifier (e.g DID) of the subject to which the verifiable credential will be issued.
example: did:prism:subjectofverifiablecredentials
validityPeriod:
type: number
description: The validity period in seconds of the verifiable credential that will be issued.
example: 3600
claims:
type: object
description: The claims that will be associated with the issued verifiable credential.
additionalProperties:
type: string
automaticIssuance:
description: |
Specifies whether or not the credential should be automatically generated and issued when receiving the `CredentialRequest` from the holder.
If set to `false`, a manual approval by the issuer via API call will be required for the VC to be issued.
type: boolean
default: true

CreateIssueCredentialRecordRequest:
description: A request to create a new "issue credential record".
type: object
allOf:
- $ref: "#/components/schemas/IssueCredentialRecordBase"
- type: object
required:
- issuingDID
- connectionId
properties:
issuingDID:
type: string
description: The issuer DID of the verifiable credential object.
example: did:prism:issuerofverifiablecredentials
connectionId:
type: string
description: The unique identifier of a DIDComm connection that already exists between the issuer and the holder, and that will be used to execute the issue credential protocol.

AcceptCredentialOfferRequest:
description: A request to accept a credential offer received from an issuer.
type: object
required:
- subjectId
properties:
subjectId:
type: string
description: The short-form subject Prism DID to which the verifiable credential should be issued.
example: did:prism:3bb0505d13fcb04d28a48234edb27b0d4e6d7e18a81e2c1abab58f3bbc21ce6f

IssueCredentialRecord:
description: An issue credential record that stores the state of the protocol execution.
type: object
allOf:
- $ref: "#/components/schemas/IssueCredentialRecordBase"
- type: object
required:
- recordId
- createdAt
- role
- protocolState
properties:
recordId:
description: The unique identifier of the issue credential record.
type: string
# format: uuid
createdAt:
description: The date and time when the issue credential record was created.
type: string
format: date-time
updatedAt:
description: The date and time when the issue credential record was last updated.
type: string
format: date-time
role:
description: The role played by the Prism agent in the credential issuance flow.
type: string
enum:
- Issuer
- Holder
protocolState:
description: The current state of the issue credential protocol execution.
type: string
enum:
- OfferPending
- OfferSent
- OfferReceived
- RequestPending
- RequestGenerated
- RequestSent
- RequestReceived
- ProblemReportPending
- ProblemReportSent
- ProblemReportReceived
- CredentialPending
- CredentialSent
- CredentialReceived
jwtCredential:
description: The base64-encoded JWT verifiable credential that has been sent by the issuer.
type: string
issuingDID:
type: string
description: Issuer DID of the verifiable credential object.
example: did:prism:issuerofverifiablecredentials

IssueCredentialRecordPage:
allOf:
- $ref: "../shared/schemas.yaml#/components/schemas/Pagination"
- type: object
required: [contents]
properties:
contents:
type: array
items:
$ref: "#/components/schemas/IssueCredentialRecord"

RevocationStatus:
description: Revocation status record
properties:
Expand Down
116 changes: 5 additions & 111 deletions prism-agent/service/api/http/prism-agent-openapi-spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -389,125 +389,19 @@ paths:
## Issue Credential Protocol

/issue-credentials/credential-offers:
post:
operationId: createCredentialOffer
tags: ["Issue Credentials Protocol"]
summary: As a credential issuer, create a new credential offer to be sent to a holder.
description: Creates a new credential offer in the database
requestBody:
description: The credential offer object.
required: true
content:
application/json:
schema:
$ref: "./pollux/schemas.yaml#/components/schemas/CreateIssueCredentialRecordRequest"
responses:
"201":
description: The issue credential record was created successfully, and is returned in the response body.
content:
application/json:
schema:
$ref: "./pollux/schemas.yaml#/components/schemas/IssueCredentialRecord"
"422":
description: The issue credential record creation failed. More information on the error can be found in the response body.
content:
application/json:
schema:
$ref: "./shared/schemas.yaml#/components/schemas/ErrorResponse"
$ref: "./tapir-generated.yaml#/paths/~1issue-credentials~1credential-offers"

/issue-credentials/records:
get:
operationId: getCredentialRecords
tags: ["Issue Credentials Protocol"]
summary: Gets the list of issue credential records.
description: Get the list of issue credential records paginated
parameters:
- $ref: "./shared/parameters.yaml#/components/parameters/offset"
- $ref: "./shared/parameters.yaml#/components/parameters/limit"
- name: thid
in: query
description: The thid of a DIDComm communication.
required: false
schema:
type: string
responses:
"200":
description: The list of issue credential records.
content:
application/json:
schema:
$ref: "./pollux/schemas.yaml#/components/schemas/IssueCredentialRecordPage"
"500":
$ref: "./shared/responses.yaml#/components/responses/InternalServerError"
$ref: "./tapir-generated.yaml#/paths/~1issue-credentials~1records"

/issue-credentials/records/{recordId}:
get:
operationId: getCredentialRecord
tags: ["Issue Credentials Protocol"]
summary: Gets an existing issue credential record by its unique identifier.
description: Gets issue credential records by record id
parameters:
- $ref: "./pollux/parameters.yaml#/components/parameters/issueCredentialRecordIdInPath"
responses:
"200":
description: The issue credential record.
content:
application/json:
schema:
$ref: "./pollux/schemas.yaml#/components/schemas/IssueCredentialRecord"
"404":
$ref: "./shared/responses.yaml#/components/responses/NotFound"
"500":
$ref: "./shared/responses.yaml#/components/responses/InternalServerError"
$ref: "./tapir-generated.yaml#/paths/~1issue-credentials~1records~1{recordId}"

/issue-credentials/records/{recordId}/accept-offer:
post:
operationId: acceptCredentialOffer
tags: ["Issue Credentials Protocol"]
summary: As a holder, accepts a credential offer received from an issuer.
description: Accepts a credential offer received from a VC issuer and sends back a credential request.
parameters:
- $ref: "./pollux/parameters.yaml#/components/parameters/issueCredentialRecordIdInPath"
requestBody:
description: The accept credential offer request object.
required: true
content:
application/json:
schema:
$ref: ./pollux/schemas.yaml#/components/schemas/AcceptCredentialOfferRequest
responses:
"200":
description: The issue credential offer was successfully accepted.
content:
application/json:
schema:
$ref: ./pollux/schemas.yaml#/components/schemas/IssueCredentialRecord
"404":
$ref: "./shared/responses.yaml#/components/responses/NotFound"
"500":
$ref: "./shared/responses.yaml#/components/responses/InternalServerError"
$ref: "./tapir-generated.yaml#/paths/~1issue-credentials~1records~1{recordId}~1accept-offer"

/issue-credentials/records/{recordId}/issue-credential:
post:
operationId: issueCredential
tags: ["Issue Credentials Protocol"]
summary: As an issuer, issues the verifiable credential related to the specified record.
description: |
Sends credential to a holder (holder DID is specified in credential as subjectDid).
Credential is constructed from the credential records found by credential id.
parameters:
- $ref: ./pollux/parameters.yaml#/components/parameters/issueCredentialRecordIdInPath
responses:
"200":
description: The request was processed successfully and the credential will be issued asynchronously.
content:
application/json:
schema:
$ref: ./pollux/schemas.yaml#/components/schemas/IssueCredentialRecord
"404":
$ref: "./shared/responses.yaml#/components/responses/NotFound"
"500":
$ref: "./shared/responses.yaml#/components/responses/InternalServerError"
$ref: "./tapir-generated.yaml#/paths/~1issue-credentials~1records~1{recordId}~1issue-credential"

## Present proof

Expand Down
Loading

0 comments on commit 9b1558f

Please sign in to comment.