From ca2ceaf0108f5f5e63ad3313e261ead84d4ce151 Mon Sep 17 00:00:00 2001 From: Daniel Mader Date: Sat, 21 Sep 2024 18:20:00 +0200 Subject: [PATCH] docs: update OpenAPI reference --- .../{generated.openapi.yaml => openapi.yaml} | 119 ++++++++++++++---- agent_api_rest/src/holder/openid4vci/mod.rs | 9 +- .../issuance/credential_issuer/credential.rs | 9 +- .../src/issuance/credential_issuer/token.rs | 11 ++ .../well_known/oauth_authorization_server.rs | 7 +- .../well_known/openid_credential_issuer.rs | 7 +- agent_api_rest/src/lib.rs | 35 +++--- agent_api_rest/src/openapi.rs | 8 -- .../verification/authorization_requests.rs | 12 +- .../verification/relying_party/redirect.rs | 11 ++ .../src/verification/relying_party/request.rs | 12 ++ 11 files changed, 169 insertions(+), 71 deletions(-) rename agent_api_rest/{generated.openapi.yaml => openapi.yaml} (62%) diff --git a/agent_api_rest/generated.openapi.yaml b/agent_api_rest/openapi.yaml similarity index 62% rename from agent_api_rest/generated.openapi.yaml rename to agent_api_rest/openapi.yaml index 7c9f4e3d..e2c1a80e 100644 --- a/agent_api_rest/generated.openapi.yaml +++ b/agent_api_rest/openapi.yaml @@ -7,13 +7,15 @@ info: version: '' servers: - url: https://arty-aragorn.agent-dev.impierce.com + description: UniCore development server hosted by Impierce Technologies paths: /.well-known/oauth-authorization-server: get: tags: - - Well-Known + - Well-known + - (public) summary: Authorization Server Metadata - description: Returns the Authorization Server Metadata. + description: Standard OpenID Connect discovery endpoint for authorization metadata. operationId: oauth_authorization_server responses: '200': @@ -27,9 +29,10 @@ paths: /.well-known/openid-credential-issuer: get: tags: - - Well-Known + - Well-known + - (public) summary: Credential Issuer Metadata - description: Returns the Credential Issuer Metadata. + description: Standard OpenID Connect discovery endpoint for issuer metadata. operationId: openid_credential_issuer responses: '200': @@ -40,12 +43,30 @@ paths: type: array items: $ref: '#/components/schemas/CredentialIssuerMetadata' + /auth/token: + post: + tags: + - (public) + summary: Token Endpoint + description: Standard OAuth 2.0 endpoint that returns an access_token after successful authorization. + operationId: token + requestBody: + description: '' + content: + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/TokenRequest' + required: true + responses: + '200': + description: Returns an access token. /openid4vci/credential: post: tags: - - OpenID4VCI - summary: Fetch credentials - description: A wallet uses this endpoint as part of an issuance flow to fetch the credentials from. + - Issuance + - (public) + summary: Credential Endpoint + description: Standard OpenID4VCI endpoint for redeeming a token for a credential. operationId: credential requestBody: content: @@ -55,13 +76,20 @@ paths: required: true responses: '200': - description: List all credentials successfully + description: Successfully returns the credential + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/CredentialResponse' /openid4vci/offers: get: tags: - - OpenID4VCI - summary: Get an offer - description: Retrieve offer if it exists. + - Holder + - (public) + summary: Credential Offer Endpoint + description: Standard OpenID4VCI endpoint that allows the issuer to pass information to the wallet. operationId: offers requestBody: description: '' @@ -71,13 +99,47 @@ paths: required: true responses: '200': - description: Successfully retrieved offer. + description: Successfully received offer metadata. + /redirect: + post: + tags: + - (public) + summary: Redirect Endpoint + description: Standard OAuth 2.0 endpoint. + operationId: redirect + requestBody: + description: '' + content: + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/GenericAuthorizationResponse' + required: true + responses: {} + /request/{id}: + get: + tags: + - (public) + summary: Authorization Request + description: |- + Standard OAuth 2.0 endpoint. + + Instead of directly embedding the Authorization Request into a QR-code or deeplink, the `Relying Party` can embed a + `request_uri` that points to this endpoint from where the Authorization Request Object can be retrieved. + As described here: https://www.rfc-editor.org/rfc/rfc9101.html#name-passing-a-request-object-by- + operationId: request + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: {} /v0/authorization_requests: post: tags: - Verification - summary: Create an authorization request - description: Foobar + summary: Create a new Authorization Request + description: UniCore will ask a holder for certain information based on the Presentation Definition specified. operationId: authorization_requests requestBody: content: @@ -86,14 +148,14 @@ paths: $ref: '#/components/schemas/AuthorizationRequestsEndpointRequest' required: true responses: - '200': - description: '' + '201': + description: Authorization Request successfully created. /v0/authorization_requests/{id}: get: tags: - Verification - summary: Get an authorization request - description: Foobar + summary: Get an Authorization Request + description: Retrieve an existing Authorization Request. operationId: get_authorization_requests parameters: - name: id @@ -103,7 +165,13 @@ paths: type: string responses: '200': - description: '' + description: Successfully returns an existing Authorization Request. + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/GenericAuthorizationRequest' /v0/credentials: post: tags: @@ -133,7 +201,9 @@ paths: description: Unique identitfier of the Credential required: true schema: - type: string + type: integer + format: int64 + minimum: 0 responses: '200': description: Credential found @@ -228,10 +298,7 @@ components: offerId: type: string tags: -- name: OpenID4VCI - description: All operations revolved around the OpenID4VCI standard. - externalDocs: - url: https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html - description: OpenID for Verifiable Credential Issuance -- name: Well-Known +- name: (public) + description: A collection of endpoints that should be publicly accessible without authentication. They are used to resolve metadata or allow communication with wallets. +- name: Well-known description: Well-known endpoints provide metadata about the server. diff --git a/agent_api_rest/src/holder/openid4vci/mod.rs b/agent_api_rest/src/holder/openid4vci/mod.rs index 351c2a29..ccb4a5c2 100644 --- a/agent_api_rest/src/holder/openid4vci/mod.rs +++ b/agent_api_rest/src/holder/openid4vci/mod.rs @@ -16,15 +16,16 @@ pub struct Oid4vciOfferEndpointRequest { pub credential_offer: CredentialOffer, } -/// Get an offer +/// Credential Offer Endpoint /// -/// Retrieve offer if it exists. +/// Standard OpenID4VCI endpoint that allows the issuer to pass information to the wallet. #[utoipa::path( get, path = "/openid4vci/offers", - tag = "OpenID4VCI", + tag = "Holder", + tags = ["(public)"], responses( - (status = 200, description = "Successfully retrieved offer."), + (status = 200, description = "Successfully received offer metadata."), ) )] #[axum_macros::debug_handler] diff --git a/agent_api_rest/src/issuance/credential_issuer/credential.rs b/agent_api_rest/src/issuance/credential_issuer/credential.rs index 5bbdaee2..157526a8 100644 --- a/agent_api_rest/src/issuance/credential_issuer/credential.rs +++ b/agent_api_rest/src/issuance/credential_issuer/credential.rs @@ -27,18 +27,19 @@ use tracing::{error, info}; const DEFAULT_EXTERNAL_SERVER_RESPONSE_TIMEOUT_MS: u64 = 1000; const POLLING_INTERVAL_MS: u64 = 100; -/// Fetch credentials +/// Credential Endpoint /// -/// A wallet uses this endpoint as part of an issuance flow to fetch the credentials from. +/// Standard OpenID4VCI endpoint for redeeming a token for a credential. #[utoipa::path( post, path = "/openid4vci/credential", // TODO: doesn't work since (external) `CredentialRequest` doesn't implement `ToSchema`? // See: https://github.com/juhaku/utoipa?tab=readme-ov-file#how-to-implement-toschema-for-external-type request_body = CredentialRequest, - tag = "OpenID4VCI", + tag = "Issuance", + tags = ["(public)"], responses( - (status = 200, description = "List all credentials successfully") + (status = 200, description = "Successfully returns the credential", body = [CredentialResponse]) ) )] #[axum_macros::debug_handler] diff --git a/agent_api_rest/src/issuance/credential_issuer/token.rs b/agent_api_rest/src/issuance/credential_issuer/token.rs index 72728ad5..08ebfac7 100644 --- a/agent_api_rest/src/issuance/credential_issuer/token.rs +++ b/agent_api_rest/src/issuance/credential_issuer/token.rs @@ -16,6 +16,17 @@ use oid4vci::token_request::TokenRequest; use serde_json::json; use tracing::info; +/// Token Endpoint +/// +/// Standard OAuth 2.0 endpoint that returns an access_token after successful authorization. +#[utoipa::path( + post, + path = "/auth/token", + tags = ["(public)"], + responses( + (status = 200, description = "Returns an access token."), + ) +)] #[axum_macros::debug_handler] pub(crate) async fn token( State(state): State, diff --git a/agent_api_rest/src/issuance/credential_issuer/well_known/oauth_authorization_server.rs b/agent_api_rest/src/issuance/credential_issuer/well_known/oauth_authorization_server.rs index 6b9784a0..b79aef77 100644 --- a/agent_api_rest/src/issuance/credential_issuer/well_known/oauth_authorization_server.rs +++ b/agent_api_rest/src/issuance/credential_issuer/well_known/oauth_authorization_server.rs @@ -11,11 +11,12 @@ use axum::{ /// Authorization Server Metadata /// -/// Returns the Authorization Server Metadata. +/// Standard OpenID Connect discovery endpoint for authorization metadata. #[utoipa::path( get, - path = "/oauth-authorization-server", - tag = "Well-Known", + path = "/.well-known/oauth-authorization-server", + tag = "Well-known", + tags = ["(public)"], responses( (status = 200, description = "Successfully returns the Authorization Server Metadata", body = [AuthorizationServerMetadata]) ) diff --git a/agent_api_rest/src/issuance/credential_issuer/well_known/openid_credential_issuer.rs b/agent_api_rest/src/issuance/credential_issuer/well_known/openid_credential_issuer.rs index 2e96b433..fc4bdf4a 100644 --- a/agent_api_rest/src/issuance/credential_issuer/well_known/openid_credential_issuer.rs +++ b/agent_api_rest/src/issuance/credential_issuer/well_known/openid_credential_issuer.rs @@ -11,11 +11,12 @@ use axum::{ /// Credential Issuer Metadata /// -/// Returns the Credential Issuer Metadata. +/// Standard OpenID Connect discovery endpoint for issuer metadata. #[utoipa::path( get, - path = "/openid-credential-issuer", - tag = "Well-Known", + path = "/.well-known/openid-credential-issuer", + tag = "Well-known", + tags = ["(public)"], responses( (status = 200, description = "Successfully returns the Credential Issuer Metadata", body = [CredentialIssuerMetadata]) ) diff --git a/agent_api_rest/src/lib.rs b/agent_api_rest/src/lib.rs index 69c69cab..9957b0c3 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, WellKnownApi}; +use crate::openapi::{HolderApi, IssuanceApi, VerificationApi}; pub const API_VERSION: &str = "/v0"; @@ -93,30 +93,30 @@ fn get_base_path() -> Result { }) } -// #[derive(OpenApi)] -// #[openapi(modifiers(), nest((path = "/v0/todos", api = WellKnownApi)), tags((name = "well-known")))] -// struct ApiDoc; - #[derive(utoipa::OpenApi)] #[openapi( // modifiers(), + paths( + // Standard endpoints as defined in the protocol specifications. + // OAuth 2.0 + crate::verification::relying_party::redirect::redirect, + crate::verification::relying_party::request::request, + crate::issuance::credential_issuer::token::token, + // OpenID4VCI + crate::holder::openid4vci::offers, + crate::issuance::credential_issuer::credential::credential, + // .well-known + crate::issuance::credential_issuer::well_known::oauth_authorization_server::oauth_authorization_server, + crate::issuance::credential_issuer::well_known::openid_credential_issuer::openid_credential_issuer, + ), nest( - (path = "/.well-known", api = WellKnownApi), (path = "/v0", api = IssuanceApi), (path = "/v0", api = VerificationApi), (path = "/v0", api = HolderApi) ), - paths( - crate::holder::openid4vci::offers, - crate::issuance::credential_issuer::credential::credential, - ), - // paths( - // crate::issuance::credential_issuer::CredentialApi - // ), tags( - // (name = "todo", description = "Todo items management API"), - (name = "OpenID4VCI", description = "All operations revolved around the OpenID4VCI standard.", external_docs(url = "https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html", description = "OpenID for Verifiable Credential Issuance")), - (name = "Well-Known", description = "Well-known endpoints provide metadata about the server."), + (name = "(public)", description = "A collection of endpoints that should be publicly accessible without authentication. They are used to resolve metadata or allow communication with wallets."), + (name = "Well-known", description = "Well-known endpoints provide metadata about the server.") ) )] pub struct ApiDoc; @@ -124,10 +124,11 @@ pub struct ApiDoc; pub fn patch_generated_openapi(mut openapi: utoipa::openapi::OpenApi) -> utoipa::openapi::OpenApi { openapi.info.title = "UniCore HTTP API".into(); openapi.info.description = Some("Full HTTP API reference for the UniCore SSI Agent".to_string()); - // openapi.info.version = "1.0.0-alpha.1".into(); // can this be determined or does it need to be removed from the openapi.yaml? + // openapi.info.version = "1.0.0-alpha.1".into(); // can UniCore even be aware of its current version or does it need to be removed from the openapi.yaml? openapi.info.version = "".into(); openapi.servers = vec![ServerBuilder::new() .url("https://arty-aragorn.agent-dev.impierce.com") + .description(Some("UniCore development server hosted by Impierce Technologies")) .build()] .into(); openapi diff --git a/agent_api_rest/src/openapi.rs b/agent_api_rest/src/openapi.rs index 44fc8dc7..a2b2a6ce 100644 --- a/agent_api_rest/src/openapi.rs +++ b/agent_api_rest/src/openapi.rs @@ -1,7 +1,6 @@ use utoipa::OpenApi; use crate::holder::holder; -use crate::issuance::credential_issuer::well_known::{oauth_authorization_server, openid_credential_issuer}; use crate::issuance::credentials::{self, CredentialsEndpointRequest}; use crate::issuance::offers; use crate::verification::authorization_requests; @@ -29,10 +28,3 @@ pub(crate) struct VerificationApi; holder::offers::reject::reject ))] pub(crate) struct HolderApi; - -#[derive(OpenApi)] -#[openapi( - paths(oauth_authorization_server::oauth_authorization_server, openid_credential_issuer::openid_credential_issuer), - // components(schemas(Todo, TodoError)) -)] -pub(crate) struct WellKnownApi; diff --git a/agent_api_rest/src/verification/authorization_requests.rs b/agent_api_rest/src/verification/authorization_requests.rs index 9976dbdf..36c1cb49 100644 --- a/agent_api_rest/src/verification/authorization_requests.rs +++ b/agent_api_rest/src/verification/authorization_requests.rs @@ -20,15 +20,15 @@ use serde_json::Value; use tracing::info; use utoipa::ToSchema; -/// Get an authorization request +/// Get an Authorization Request /// -/// Foobar +/// Retrieve an existing Authorization Request. #[utoipa::path( get, path = "/authorization_requests/{id}", tag = "Verification", responses( - (status = 200, description = "") + (status = 200, description = "Successfully returns an existing Authorization Request.", body = [GenericAuthorizationRequest]) ) )] #[axum_macros::debug_handler] @@ -62,16 +62,16 @@ pub enum PresentationDefinitionResource { PresentationDefinition(PresentationDefinition), } -/// Create an authorization request +/// Create a new Authorization Request /// -/// Foobar +/// UniCore will ask a holder for certain information based on the Presentation Definition specified. #[utoipa::path( post, path = "/authorization_requests", request_body = AuthorizationRequestsEndpointRequest, tag = "Verification", responses( - (status = 200, description = "") + (status = 201, description = "Authorization Request successfully created."), ) )] #[axum_macros::debug_handler] diff --git a/agent_api_rest/src/verification/relying_party/redirect.rs b/agent_api_rest/src/verification/relying_party/redirect.rs index 7e315071..8e6258dd 100644 --- a/agent_api_rest/src/verification/relying_party/redirect.rs +++ b/agent_api_rest/src/verification/relying_party/redirect.rs @@ -10,6 +10,17 @@ use axum::{ Form, }; +/// Redirect Endpoint +/// +/// Standard OAuth 2.0 endpoint. +#[utoipa::path( + post, + path = "/redirect", + tags = ["(public)"], + responses( + // (status = 200, description = ""), + ) +)] #[axum_macros::debug_handler] pub(crate) async fn redirect( State(verification_state): State, diff --git a/agent_api_rest/src/verification/relying_party/request.rs b/agent_api_rest/src/verification/relying_party/request.rs index ff73e918..8c892791 100644 --- a/agent_api_rest/src/verification/relying_party/request.rs +++ b/agent_api_rest/src/verification/relying_party/request.rs @@ -7,9 +7,21 @@ use axum::{ }; use hyper::header; +/// Authorization Request +/// +/// Standard OAuth 2.0 endpoint. +/// /// Instead of directly embedding the Authorization Request into a QR-code or deeplink, the `Relying Party` can embed a /// `request_uri` that points to this endpoint from where the Authorization Request Object can be retrieved. /// As described here: https://www.rfc-editor.org/rfc/rfc9101.html#name-passing-a-request-object-by- +#[utoipa::path( + get, + path = "/request/{id}", + tags = ["(public)"], + responses( + // (status = 200, description = ""), + ) +)] #[axum_macros::debug_handler] pub(crate) async fn request( State(verification_state): State,