From 35a8d1197c8d9d2c322ec01e958a3a0ebc31cb03 Mon Sep 17 00:00:00 2001 From: Daniel Mader Date: Mon, 30 Sep 2024 01:28:33 +0200 Subject: [PATCH] docs: add missing endpoints --- agent_api_rest/openapi.yaml | 64 +++++++++++++++++-- .../src/holder/holder/offers/accept.rs | 2 +- .../src/holder/holder/offers/reject.rs | 2 +- agent_api_rest/src/holder/openid4vci/mod.rs | 4 +- agent_api_rest/src/issuance/credentials.rs | 6 +- agent_api_rest/src/issuance/offers/send.rs | 12 ++++ agent_api_rest/src/lib.rs | 7 +- agent_api_rest/src/openapi.rs | 57 ++++++++++++++++- 8 files changed, 139 insertions(+), 15 deletions(-) diff --git a/agent_api_rest/openapi.yaml b/agent_api_rest/openapi.yaml index e779a14d..4260f664 100644 --- a/agent_api_rest/openapi.yaml +++ b/agent_api_rest/openapi.yaml @@ -9,6 +9,40 @@ servers: - url: https://playground.agent-dev.impierce.com description: UniCore development server hosted by Impierce Technologies paths: + /.well-known/did-configuration.json: + get: + tags: + - (.well-known) + - (public) + summary: DID Configuration Resource for Domain Linkage + description: Standard .well-known endpoint for DID Configuration Resources. + operationId: did_configuration_json + responses: + '200': + description: DID Configuration Resource + content: + application/json: + schema: + $ref: '#/components/schemas/DomainLinkageConfiguration' + '404': + description: Domain Linkage inactive. + /.well-known/did.json: + get: + tags: + - (.well-known) + - (public) + summary: DID Document for `did:web` method + description: Standard .well-known endpoint for self-hosted DID Document. + operationId: did_json + responses: + '200': + description: DID Document for `did:web` method + content: + application/json: + schema: + $ref: '#/components/schemas/CoreDocument' + '404': + description: DID method `did:web` inactive. /.well-known/oauth-authorization-server: get: tags: @@ -89,7 +123,10 @@ paths: - Holder - (public) summary: Credential Offer Endpoint - description: Standard OpenID4VCI endpoint that allows the issuer to pass information to the wallet. + description: |- + Standard OpenID4VCI endpoint that allows the Issuer to pass information about the credential offer to the Holder's wallet. + + [Specification](https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-credential-offer-endpoint) operationId: offers requestBody: description: '' @@ -233,9 +270,9 @@ paths: /v0/credentials/{id}: get: tags: - - Credentials + - Issuance summary: Retrieve a credential - description: Return a credential for a given ID. + description: Retrieves an existing credential by its ID. operationId: get_credentials parameters: - name: id @@ -244,6 +281,7 @@ paths: required: true schema: type: string + example: '0001' responses: '200': description: Credential found @@ -278,7 +316,7 @@ paths: tags: - Holder summary: Accept an offer - description: Accepts a pending credential offer. + description: Accept a pending credential offer. UniCore will then make a request to the Issuer to receive the offer. operationId: accept parameters: - name: offer_id @@ -294,7 +332,7 @@ paths: tags: - Holder summary: Reject an offer - description: Reject a pending credential offer. + description: Reject a pending credential offer. UniCore will not make any further requests to the Issuer. operationId: reject parameters: - name: offer_id @@ -326,6 +364,22 @@ paths: schema: type: string example: openid-credential-offer://?credential_offer=%7B%22credential_issuer%22%3A%22https%3A%2F%2Fcredential-issuer.example.com%2F%22%2C%22credentials%22%3A%5B%7B%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww.w3.org%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww.w3.org%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22type%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%7D%5D%7D + /v0/offers/send: + post: + tags: + - Issuance + summary: Send offer to Holder + description: Sends a prepared credential offer to a Holder's [Credential Offer Endpoint](#tag/holder/GET/openid4vci/offers) via a `GET` request. + operationId: send + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SendOfferEndpointRequest' + required: true + responses: + '200': + description: Successfully sent credential offer to Holder. components: schemas: CredentialsEndpointRequest: diff --git a/agent_api_rest/src/holder/holder/offers/accept.rs b/agent_api_rest/src/holder/holder/offers/accept.rs index 0bde101c..d7fa2e90 100644 --- a/agent_api_rest/src/holder/holder/offers/accept.rs +++ b/agent_api_rest/src/holder/holder/offers/accept.rs @@ -12,7 +12,7 @@ use hyper::StatusCode; /// Accept an offer /// -/// Accepts a pending credential offer. +/// Accept a pending credential offer. UniCore will then make a request to the Issuer to receive the offer. #[utoipa::path( post, path = "/holder/offers/{offer_id}/accept", diff --git a/agent_api_rest/src/holder/holder/offers/reject.rs b/agent_api_rest/src/holder/holder/offers/reject.rs index c8d8311f..fb1ebd58 100644 --- a/agent_api_rest/src/holder/holder/offers/reject.rs +++ b/agent_api_rest/src/holder/holder/offers/reject.rs @@ -8,7 +8,7 @@ use hyper::StatusCode; /// Reject an offer /// -/// Reject a pending credential offer. +/// Reject a pending credential offer. UniCore will not make any further requests to the Issuer. #[utoipa::path( post, path = "/holder/offers/{offer_id}/reject", diff --git a/agent_api_rest/src/holder/openid4vci/mod.rs b/agent_api_rest/src/holder/openid4vci/mod.rs index ccb4a5c2..133a8760 100644 --- a/agent_api_rest/src/holder/openid4vci/mod.rs +++ b/agent_api_rest/src/holder/openid4vci/mod.rs @@ -18,7 +18,9 @@ pub struct Oid4vciOfferEndpointRequest { /// Credential Offer Endpoint /// -/// Standard OpenID4VCI endpoint that allows the issuer to pass information to the wallet. +/// Standard OpenID4VCI endpoint that allows the Issuer to pass information about the credential offer to the Holder's wallet. +/// +/// [Specification](https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-credential-offer-endpoint) #[utoipa::path( get, path = "/openid4vci/offers", diff --git a/agent_api_rest/src/issuance/credentials.rs b/agent_api_rest/src/issuance/credentials.rs index f66e2342..5f70156d 100644 --- a/agent_api_rest/src/issuance/credentials.rs +++ b/agent_api_rest/src/issuance/credentials.rs @@ -20,13 +20,13 @@ use utoipa::ToSchema; /// Retrieve a credential /// -/// Return a credential for a given ID. +/// Retrieves an existing credential by its ID. #[utoipa::path( get, path = "/credentials/{id}", - tag = "Credentials", + tag = "Issuance", params( - ("id" = String, Path, description = "Unique identifier of the Credential"), + ("id" = String, Path, description = "Unique identifier of the Credential", example = "0001"), ), responses( (status = 200, description = "Credential found", body = [CredentialView]) diff --git a/agent_api_rest/src/issuance/offers/send.rs b/agent_api_rest/src/issuance/offers/send.rs index 2e9a973a..d2fd9a41 100644 --- a/agent_api_rest/src/issuance/offers/send.rs +++ b/agent_api_rest/src/issuance/offers/send.rs @@ -17,6 +17,18 @@ pub struct SendOfferEndpointRequest { pub target_url: Url, } +/// Send offer to Holder +/// +/// Sends a prepared credential offer to a Holder's [Credential Offer Endpoint](#tag/holder/GET/openid4vci/offers) via a `GET` request. +#[utoipa::path( + post, + path = "/offers/send", + request_body = SendOfferEndpointRequest, + tag = "Issuance", + responses( + (status = 200, description = "Successfully sent credential offer to Holder."), + ) +)] #[axum_macros::debug_handler] pub(crate) async fn send(State(state): State, Json(payload): Json) -> Response { info!("Request Body: {}", payload); diff --git a/agent_api_rest/src/lib.rs b/agent_api_rest/src/lib.rs index bce7b0ba..d81ac93a 100644 --- a/agent_api_rest/src/lib.rs +++ b/agent_api_rest/src/lib.rs @@ -13,7 +13,7 @@ use tracing::{info_span, Span}; use utoipa::{openapi::ServerBuilder, OpenApi}; use utoipa_scalar::{Scalar, Servable}; -use crate::openapi::{HolderApi, IssuanceApi, VerificationApi}; +use crate::openapi::{did_configuration, did_web, HolderApi, IssuanceApi, VerificationApi}; pub const API_VERSION: &str = "/v0"; @@ -134,6 +134,11 @@ pub fn patch_generated_openapi(mut openapi: utoipa::openapi::OpenApi) -> utoipa: .description(Some("UniCore development server hosted by Impierce Technologies")) .build()] .into(); + // Append endpoints defined outside of `agent_api_rest`. + openapi.paths.add_path("/.well-known/did.json", did_web()); + openapi + .paths + .add_path("/.well-known/did-configuration.json", did_configuration()); openapi } diff --git a/agent_api_rest/src/openapi.rs b/agent_api_rest/src/openapi.rs index a2b2a6ce..95293a26 100644 --- a/agent_api_rest/src/openapi.rs +++ b/agent_api_rest/src/openapi.rs @@ -1,3 +1,5 @@ +use utoipa::openapi::path::OperationBuilder; +use utoipa::openapi::{Content, HttpMethod, PathItem, Ref, Response, ResponseBuilder, ResponsesBuilder}; use utoipa::OpenApi; use crate::holder::holder; @@ -7,9 +9,13 @@ use crate::verification::authorization_requests; #[derive(OpenApi)] #[openapi( - // paths(credential::credential, credentials, get_credentials), - paths(credentials::credentials, credentials::get_credentials, offers::offers), - components(schemas(CredentialsEndpointRequest)) + paths( + credentials::credentials, + credentials::get_credentials, + offers::offers, + offers::send::send + ), + components(schemas(CredentialsEndpointRequest)) )] pub(crate) struct IssuanceApi; @@ -28,3 +34,48 @@ pub(crate) struct VerificationApi; holder::offers::reject::reject ))] pub(crate) struct HolderApi; + +pub(crate) fn did_web() -> PathItem { + PathItem::new( + HttpMethod::Get, + OperationBuilder::new() + .responses( + ResponsesBuilder::new() + .response( + "200", + ResponseBuilder::new() + .description("DID Document for `did:web` method") + .content("application/json", Content::new(Ref::from_schema_name("CoreDocument"))), + ) + .response("404", Response::new("DID method `did:web` inactive.")), + ) + .operation_id(Some("did_json")) + .summary(Some("DID Document for `did:web` method")) + .description(Some("Standard .well-known endpoint for self-hosted DID Document.")) + .tags(Some(vec!["(.well-known)", "(public)"])), + ) +} + +pub(crate) fn did_configuration() -> PathItem { + PathItem::new( + HttpMethod::Get, + OperationBuilder::new() + .responses( + ResponsesBuilder::new() + .response( + "200", + ResponseBuilder::new() + .description("DID Configuration Resource") + .content( + "application/json", + Content::new(Ref::from_schema_name("DomainLinkageConfiguration")), + ), + ) + .response("404", Response::new("Domain Linkage inactive.")), + ) + .operation_id(Some("did_configuration_json")) + .summary(Some("DID Configuration Resource for Domain Linkage")) + .description(Some("Standard .well-known endpoint for DID Configuration Resources.")) + .tags(Some(vec!["(.well-known)", "(public)"])), + ) +}