Skip to main content

Introduction

The VCVerifier API provides endpoints for implementing SIOP-2 and OIDC4VP compliant authentication flows. It exchanges Verifiable Credentials for JWT tokens that can be used for authorization and authentication in downstream components.
VCVerifier acts as a Relying Party in the SIOP-2 specification, verifying credentials and issuing JWT tokens for authenticated sessions.

Base URL

The API is served on port 8080 by default. For production deployments:
https://your-domain.com/
For local development:
http://localhost:8080/

API Endpoints

Frontend Endpoints

Endpoints for browser-based H2M interactions with QR code flows

API Endpoints

RESTful endpoints for M2M integrations and programmatic access

OpenID Configuration

Standard OpenID Connect discovery and configuration endpoints

Token Exchange

OAuth 2.0 compliant token endpoints for retrieving JWTs

Authentication Overview

VCVerifier uses a multi-step authentication flow:
  1. Initiation: Client starts the flow via authorization or login endpoints
  2. Presentation: User presents Verifiable Credentials via wallet
  3. Verification: VCVerifier validates credentials against trusted registries
  4. Token Issuance: JWT access token is generated with credential claims
All credentials are verified against configured Trusted Issuers Registries (TIR) and Trusted Participants Lists before tokens are issued.

Frontend Endpoints

These endpoints are designed for human-to-machine (H2M) interactions.

Login with QR Code (v1)

GET /api/v1/loginQR Presents a rendered HTML page with a QR code for initiating the SIOP flow. Parameters:
state
string
required
Session state identifier (UUID format recommended)Example: 274e7465-cc9d-4cad-b75f-190db927e56a
client_callback
string (URL)
required
Endpoint to receive the authentication callback with state and codeExample: https://my-portal.com/auth_callback
client_id
string
default:"optional"
Service identifier for retrieving scope and trust configurationExample: packet-delivery-portal
nonce
string
required
Cryptographic nonce for replay protectionExample: 274e7465-cc9d-4cad-b75f-190db927e56a
request_mode
enum
default:"byReference"
Mode for authorization request encodingOptions: urlEncoded, byValue, byReference
Responses:
200
text/html
Rendered HTML page containing the QR code for wallet scanning
400
application/json
Invalid request parameters
{
  "summary": "Missing Input",
  "details": "Expected 'state' as a query parameter."
}

Login with QR Code (v2)

GET /api/v2/loginQR Enhanced version with additional parameters for more flexible authentication flows. Parameters: Includes all v1 parameters plus:
redirect_uri
string (URL)
default:"optional"
Custom redirect URI for the authentication responseExample: https://my-app.com/redirect
request_uri
string (URL)
default:"optional"
URI for retrieving a request object (JWT)Example: https://my-app.com/request.jwt
scope
string
default:"optional"
OpenID Connect scope for credential typesExample: openid

API Endpoints

These endpoints are designed for programmatic access and machine-to-machine (M2M) integrations.

Authorization Endpoint

GET /api/v1/authorization OAuth 2.0 compliant authorization endpoint providing redirect to the concrete authorization method. Parameters:
state
string
required
Session state identifier
client_id
string
default:"optional"
Client application identifier
redirect_uri
string (URL)
default:"optional"
Callback URI for authorization response
request_uri
string (URL)
default:"optional"
URI reference to a request object containing authorization parameters
scope
string
default:"optional"
Requested credential types/scopes
nonce
string
required
Cryptographic nonce value
response_type
enum
default:"optional"
Type of expected responseOptions: code
Responses:
302
redirect
Redirect to the authorization entry point with encoded parameters

Start SIOP Flow

GET /api/v1/startsiop Initiates the SIOP flow and returns the OpenID connection string. Parameters:
state
string
required
Session state identifier
client_callback
string (URL)
required
Endpoint to receive the JWT token
client_id
string
default:"optional"
Service identifier for configuration retrieval
Responses:
200
text/plain
OpenID connection string for wallet interaction
openid://?scope=dsba.credentials.presentation.PacketDeliveryService&response_type=vp_token&response_mode=post&client_id=did:key:z6MktZy7CErCqdLvknH6g9YNVpWupuBNBNovsBrj4DFGn4R1&redirect_uri=http://localhost:3000/verifier/api/v1/authenticationresponse&state=&nonce=BfEte4DFdlmdO7a_fBiXTw

Same Device Flow

GET /api/v1/samedevice Starts the SIOP flow for credentials held by the same device (no QR code needed). Parameters:
state
string
required
Session state identifier
client_id
string
default:"optional"
Client application identifier
scope
string
default:"optional"
Requested credential scopes
request_mode
enum
default:"byReference"
Authorization request mode
redirect_path
string
default:"optional"
Custom redirect path (defaults to oid4vp deeplink)Example: /
Responses:
302
redirect
Redirect to authentication response path with authorization parameters

Request Object by Reference

GET /api/v1/request/{id} Returns a JWT-encoded request object by reference as defined in OpenID4VP Section 5. Path Parameters:
id
string
required
Request identifier (typically UUID)Example: urn:uuid:274e7465-cc9d-4cad-b75f-190db927e56a
Responses:
200
text/html
JWT-encoded request object containing authorization parameters
400
application/json
Invalid request ID or expired request

Authentication Response (POST)

POST /api/v1/authentication_response Receives and stores the Verifiable Presentation from the wallet. Parameters:
state
string (query)
required
Session state identifier
client_id
string (query)
default:"optional"
Client application identifier
Request Body (application/x-www-form-urlencoded):
vp_token
string
required
Base64URL-encoded Verifiable Presentation containing credential(s)
presentation_submission
string
required
Base64URL-encoded Presentation Submission describing the presented credentials
Both vp_token and presentation_submission must use Base64-URL-Safe encoding (RFC 4648 Section 5), not standard Base64 encoding.
Responses:
204
No Content
Credential successfully verified and stored
400
application/json
Invalid presentation or verification failure

Authentication Response (GET)

GET /api/v1/authentication_response Alternative method for receiving authentication responses via query parameters. Parameters:
state
string
required
Session state identifier
vp_token
string
required
Base64URL-encoded Verifiable Presentation
presentation_submission
string
required
Base64URL-encoded Presentation Submission
Responses:
204
No Content
Credential successfully verified and stored

Token Exchange

Token Endpoint

POST /token OAuth 2.0 compliant token endpoint for exchanging authorization codes for JWT access tokens. Request Body (application/x-www-form-urlencoded):
grant_type
enum
required
OAuth 2.0 grant typeOptions: authorization_code, urn:ietf:params:oauth:grant-type:token-exchange
code
string
required
Authorization code from the authentication responseExample: myRandomString
redirect_uri
string (URL)
required
Same URI as provided in the original requestExample: https://my-portal.com/auth_callback
Token Exchange Parameters (when grant_type is token-exchange):
resource
string (URL)
default:"optional"
Target service URI where the token will be used
audience
string
default:"optional"
Logical name of the target service
scope
array[string]
default:"optional"
Space-delimited list of desired scopes
requested_token_type
enum
default:"optional"
Type of security token requestedOptions: urn:ietf:params:oauth:token-type:access_token
subject_token
string
default:"optional"
Security token representing the party’s identity
subject_token_type
enum
default:"optional"
Type of the subject tokenOptions: urn:eu:oidf:vp_token
Responses:
200
application/json
JWT access token and metadata
{
  "token_type": "Bearer",
  "issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
  "expires_in": 3600,
  "access_token": "eyJhbGciOiJFUzI1NiIsImtpZCI6IldPSEZ1NEhaNTlTTTg1M0M3ZU4wT3ZsS0dyTWVlckRDcEhPVVJvVFF3SHciLCJ0eXAiOiJKV1QifQ..."
}
403
application/json
Invalid or expired authorization code
{
  "summary": "Invalid Code",
  "details": "The provided authorization code is invalid or has expired."
}

Service-Specific Token Endpoint

POST /services/{service_id}/token Token endpoint scoped to a specific service configuration. Path Parameters:
service_id
string
required
Service identifier matching the configurationExample: packet-delivery-portal
Request Body: Same as the standard token endpoint.

OpenID Configuration

JWKS Endpoint

GET /.well-known/jwks Provides the public keys for verifying JWT signatures issued by the verifier. Responses:
200
application/json
JWK Set containing public keys
{
  "keys": [
    {
      "kid": "179d7b56-6598-4045-9a32-4635e8b0f605",
      "kty": "EC",
      "use": "sig",
      "alg": "ES256",
      "crv": "P-256",
      "x": "3ctHY_0KJW5ezT-oF39t3wPX6XlggWKOSPFW8iooBXk",
      "y": "HXA4mBHgObIE56E92yxN5bYQ27wSxlVPfuNWaY06TTI"
    }
  ]
}

OpenID Provider Metadata

GET /services/{service_id}/.well-known/openid-configuration Returns OpenID Provider configuration for a specific service. Path Parameters:
service_id
string
required
Service identifier
Responses:
200
application/json
OpenID Provider Metadata
{
  "issuer": "https://api-test.ebsi.eu/authorisation/v4",
  "authorization_endpoint": "https://api-test.ebsi.eu/authorisation/v4/authorize",
  "token_endpoint": "https://api-test.ebsi.eu/authorisation/v4/token",
  "presentation_definition_endpoint": "https://api-test.ebsi.eu/authorisation/v4/presentation-definitions",
  "jwks_uri": "https://api-test.ebsi.eu/authorisation/v4/jwks",
  "scopes_supported": ["openid", "didr_invite", "didr_write"],
  "response_types_supported": ["token"],
  "response_mode_supported": ["query", "fragment"],
  "grant_types_supported": ["vp_token"],
  "subject_types_supported": ["public"],
  "id_token_signing_alg_values_supported": ["ES256"],
  "request_object_signing_alg_values_supported": ["ES256"],
  "request_parameter_supported": true,
  "token_endpoint_auth_methods_supported": ["private_key_jwt"]
}

Common Response Formats

Error Response

All error responses follow a consistent format:
{
  "summary": "Error Type",
  "details": "Detailed error message explaining what went wrong."
}
Common Error Types:
  • Missing Input: Required parameter is missing
  • Invalid Credential: Credential verification failed
  • Expired Session: Authentication session has expired (default: 30 seconds)
  • Untrusted Issuer: Credential issuer not found in trusted registries
  • Invalid Code: Authorization code is invalid or expired

Error Codes

Status CodeDescriptionCommon Causes
200SuccessRequest completed successfully
204No ContentCredential stored successfully
302RedirectStandard flow redirect
400Bad RequestMissing parameters, invalid format, validation failure
403ForbiddenInvalid authorization code, untrusted issuer
404Not FoundRequest object or session not found
500Internal Server ErrorServer-side processing error

Request Modes

VCVerifier supports three modes for encoding authorization requests:

URL Encoded

Parameters are passed directly in the URL:
openid4vp://?response_type=vp_token&response_mode=direct_post&client_id=did:key:verifier&redirect_uri=https://verifier.org/api/v1/authentication_response&state=randomState&nonce=randomNonce

By Value

Parameters are encoded in a signed JWT passed as the request parameter:
openid4vp://?client_id=did:key:verifier&request=eyJhbGciOiJFUzI1NiIsInR5cCI6Im9hdXRoLWF1dGh6LXJlcStqd3QifQ...
Requires proper clientIdentification configuration with signing keys.
A reference URI is provided to retrieve the request object:
openid4vp://?client_id=did:key:verifier&request_uri=verifier.org/api/v1/request/randomState&request_uri_method=get
The byReference mode is recommended for production as it generates smaller QR codes and reduces URL length limitations.

Rate Limiting

Currently, VCVerifier does not implement rate limiting. For production deployments, consider implementing rate limiting at the reverse proxy or API gateway level.

Security Considerations

Important Security Notes:
  • Sessions expire after 30 seconds by default (configurable)
  • All credentials are verified against configured trust anchors
  • The verifier does not currently offer endpoints to prove its own identity
  • Presentation submissions are accepted but not fully evaluated
  • Only the first credential in multi-credential presentations is included in the JWT

Next Steps

Authentication Flow

Detailed authentication flow with sequence diagrams

Configuration

Learn how to configure VCVerifier for your use case

Build docs developers (and LLMs) love