commit 723cf257e7a3e644cc214e4bb359d9ce8ba8d7ad parent 4d72952ac96ecc9451b31f6a79e621ba9655bdd5 Author: Henrique Chan Carvalho Machado <henriqueccmachado@tecnico.ulisboa.pt> Date: Fri, 23 Jan 2026 12:59:30 +0100 Finish final documentation and READMEs Diffstat:
| A | README | | | 74 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | documentation/README | | | 51 | +++++++++++++++++++++++++++++++++++++++++++++++++++ |
| R | documentation/kych_logo.svg -> documentation/kych_verifier_logo.svg | | | 0 | |
| D | documentation/onboarding_verifier.tex | | | 140 | ------------------------------------------------------------------------------- |
| M | documentation/sequence_diagrams/swiyu_taler_sequence_diagram.txt | | | 4 | ++-- |
| A | documentation/taler-docs/README | | | 110 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | documentation/taler-docs/core/api-kych.rst | | | 607 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| R | documentation/kych_architecture.jpg -> documentation/taler-docs/images/kych_overview.jpg | | | 0 | |
| A | documentation/taler-docs/images/swiyu_taler_sequence_diagram.png | | | 0 | |
| A | documentation/taler-docs/kych.conf.5.rst | | | 206 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | documentation/taler-docs/manpages/kych-client-management.1.rst | | | 127 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | documentation/taler-docs/manpages/kych-oauth2-gateway.1.rst | | | 71 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | documentation/taler-docs/taler-kych-manual.rst | | | 701 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | kych_oauth2_gateway/README | | | 142 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| D | kych_oauth2_gateway/openapi.yaml | | | 313 | ------------------------------------------------------------------------------- |
| A | swiyu-verifier/README | | | 96 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
16 files changed, 2187 insertions(+), 455 deletions(-)
diff --git a/README b/README @@ -0,0 +1,74 @@ +KYCH +==== + +KYCH is an OAuth2-based identity verification system that integrates with +the Swiss SWIYU trust infrastructure. It enables services like GNU Taler +exchanges to verify user identity through SD-JWT Verifiable Credentials, +supporting privacy-preserving selective disclosure. + +For integration with GNU Taler, see documentation/taler-docs/. + + +Architecture +------------ + +The system consists of two main components working together: + + +------------------+ +-------------------+ +---------------+ + | Service | | KYCH OAuth2 | | SWIYU | + | (e.g. Taler | <---> | Gateway | <---> | Verifier | + | Exchange) | | (Rust) | | (Java) | + +------------------+ +-------------------+ +---------------+ + ^ + | + v + +------------------+ + | SWIYU Wallet | + | (User's mobile) | + +------------------+ + +1. KYCH OAuth2 Gateway (kych_oauth2_gateway/) + A Rust service implementing OAuth2 authorization code flow with + OpenID4VP (OID4VP) credential verification. + +2. SWIYU Verifier (swiyu-verifier/) + Scripts and configuration for running the SWIYU Generic Verifier locally. + +The full interaction flow between a Taler exchange, the gateway, and the +verifier is documented in: + documentation/sequence_diagrams/swiyu_taler_sequence_diagram.txt + + +Components +---------- + + kych_oauth2_gateway/ Rust OAuth2 gateway service + swiyu-verifier/ Local verifier setup scripts + documentation/ Technical specifications and sequence diagrams + + +Technology Stack +---------------- + + Gateway: Rust (Axum, Tokio, SQLx) + Verifier: Java 21, Spring Boot + Database: PostgreSQL + Credentials: SD-JWT Verifiable Credentials (vc+sd-jwt) + Protocols: OAuth 2.0, OpenID4VP, DCQL + + +Standards +--------- + + SD-JWT VC https://datatracker.ietf.org/doc/draft-ietf-oauth-sd-jwt-vc/ + OpenID4VP https://openid.net/specs/openid-4-verifiable-presentations-1_0.html + GNU Taler https://docs.taler.net/ + SWIYU Swiss e-ID Trust Infrastructure + + +Getting Started +--------------- + +1. Set up the SWIYU Verifier - see swiyu-verifier/README +2. Configure and run the OAuth2 Gateway - see kych_oauth2_gateway/README +3. Review the technical documentation in documentation/ diff --git a/documentation/README b/documentation/README @@ -0,0 +1,51 @@ +KYCH Documentation +================== + +This directory contains technical specifications and diagrams for the +KYCH system. + +For integration with GNU Taler, see the taler-docs/ directory which +contains reStructuredText documentation intended for the official +GNU Taler documentation (https://docs.taler.net/). + + +Files +----- + + vc.md Verifiable Credential format specification (SD-JWT) + vp.md Verifiable Presentation format specification + + kych_verifier_logo.svg KYCH verifier logo + + +Sequence Diagrams +----------------- + +The sequence_diagrams/ directory contains ASCII diagrams documenting +the OAuth2 and credential verification flows: + + swiyu_taler_sequence_diagram.txt + Complete end-to-end flow showing how a GNU Taler exchange + interacts with KYCH and the SWIYU verifier for KYC verification. + + setup_sequence.txt + Initial client setup and registration flow. + + authorize_sequence.txt + OAuth2 authorization request and credential verification. + + token_sequence.txt + Token exchange after successful verification. + + info_sequence.txt + User information retrieval endpoint. + + notification_sequence.txt + Webhook callback flow for verification status updates. + + +Related Standards +----------------- + + SD-JWT VC https://datatracker.ietf.org/doc/draft-ietf-oauth-sd-jwt-vc/ + OpenID4VP https://openid.net/specs/openid-4-verifiable-presentations-1_0.html diff --git a/documentation/kych_logo.svg b/documentation/kych_verifier_logo.svg diff --git a/documentation/onboarding_verifier.tex b/documentation/onboarding_verifier.tex @@ -1,140 +0,0 @@ -\documentclass{article} -\usepackage{hyperref} -\usepackage{enumitem} -\usepackage{listings} -\usepackage{xcolor} - -% Code listing settings -\lstset{ - basicstyle=\ttfamily\small, - breaklines=true, - frame=single, - backgroundcolor=\color{gray!10} -} - -\title{Onboarding the Swiyu Trust Infrastructure for a Generic Verifier} -\author{Henrique Machado} -\date{\today} - -\begin{document} -\maketitle - -\section{Introduction} - -Before being able to act as an issuer or verifier in the swiyu ecosystem, you will need to onboard onto the base registry and optionally register on the trust registry. - -Section \ref{Section 3} outlines all the steps necessary to onboard the swiyu trust infrastructure. - -\textbf{Important:} Please note that the current system is in Public Beta and is provided on a best-effort basis. The system will continue to evolve over time. - -\section{Prerequisites} - -Before starting the onboarding process, ensure you have: - -\begin{itemize} - \item An AGOV or CH-Login account for accessing the ePortal. - \item Java Runtime Environment (JRE) 21 or higher installed. - \item Sufficient disk space (approximately 100 MB). - \item Internet connection. - \item Operating system: Linux x64/AArch64, macOS (AArch64), or Windows (x64). -\end{itemize} - -\section{Onboarding Process Overview}\label{Section 3} - -The onboarding process consists of the following steps: - -\begin{enumerate} - \item Sign-in or sign-up to the Swiss Confederacy ePortal. - \item Register as Business Partner. - \item Get API keys from the self-service portal. - \item Allocate DID space on the Swiyu Base Registry. - \item Generate cryptographic keys and DID log using the swiyu DID Toolbox. - \item Create and upload the DID log. - \item (Optional) Become a trusted participant. -\end{enumerate} - -The official swiyu technical documentation offers detailed guides ---\href{https://swiyu-admin-ch.github.io/cookbooks/}{cookbooks}--- that guide you through this process in a detailed manner. Follow \href{https://swiyu-admin-ch.github.io/cookbooks/onboarding-base-and-trust-registry/}{this cookbook} to complete the necessary steps for a successful onboarding process. - -\section{Configuring the Swiyu Generic Verifier} - -With the onboarding process complete, it is necessary to configure the Swiyu Generic Verifier with the generated keys and DID. - -\subsection{Locate the Configuration File} - -The Generic Verifier uses a YAML configuration file, located in - -\texttt{/swiyu-verifier/verifier-application/src/main/resources/application.yml}. - -\subsection{Understanding the Required Configuration Parameters} - -All required parameters can be found in the DID log generated by the DID toolbox. - -\begin{itemize} - \item \textbf{client\_id:} The DID found in the value of the \texttt{value.id} field. - - \item \textbf{signing-key-verification-method:} Your DID with the authentication key reference appended. Its value is found in the \texttt{value.assertionMethod} entry in the DID log. The format is: \texttt{<your-did>\#auth-key-01} - - \item \textbf{signing-key:} The private EC authentication key from the file \texttt{.didtoolbox/auth-key-01}. Copy the entire content including the BEGIN and END markers. -\end{itemize} - -\subsection{Example Configuration} - -After replacing with your specific values, the \texttt{application.yaml} file will look similar to this: - -\begin{lstlisting}[language=yaml] -application: - signing-key: | - -----BEGIN EC PRIVATE KEY----- - MHcCAQEEIABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstu - oAoGCCqGSM49AwEHoUQDQgAE5cice+6ILYCD2gFEVFMLPt3HPf5n/Oef - zOOoP+3SLDAlh/YkKQvF/1xv0uYuvy1t6wpDM7au1dMEg2L1I9wDxE== - -----END EC PRIVATE KEY----- - signing-key-verification-method: "did:tdw:Qmd9bwsodZ1GAz4h8D7Vy6qRio78voXifDrnXokSTsMVQK:identifier-reg.trust-infra.swiyu-int.admin.ch:api:v1:did:18fa7c77-9dd1-4e20-a147-fb1bec146085#auth-key-01" - external-url: "https://yourdomain.com" - client_id: "did:tdw:Qmd9bwsodZ1GAz4h8D7Vy6qRio78voXifDrnXokSTsMVQK:identifier-reg.trust-infra.swiyu-int.admin.ch:api:v1:did:18fa7c77-9dd1-4e20-a147-fb1bec146085" - client_id_scheme: "did" - client-metadata-file: "classpath:/client_metadata.json" -\end{lstlisting} - -To make sure the Generic Verifier uses your configuration, do not forget to specify this .yaml run profile when booting the server: - -\begin{lstlisting}[language=bash] -./mvnw spring-boot:run -pl verifier-application -Dspring-boot.run.profiles=application -\end{lstlisting} - -Where 'application' is the name of the configuration .yaml file. - -\section{HTTPS Configuration for Swiyu Wallet} - -\subsection{HTTPS Requirement} - -The Swiyu wallet \textbf{only accepts HTTPS connections}. To verify BetaID credentials, you must use a valid TLS/SSL certificate and ensure your verifier is accessible via HTTPS. - -\subsection{Option 1: Public URL with Trusted Certificate} - -For easier setup, especially during development and testing, you can use a tunneling service like ngrok to forward a public HTTPS URL to your local verifier: - -\begin{enumerate} - \item Install ngrok: \url{https://ngrok.com/download} - \item Start your Generic Verifier locally (e.g., on port 8080) - \item Create an ngrok tunnel: - \begin{lstlisting}[language=bash] -ngrok http 8080 - \end{lstlisting} - \item ngrok will provide a public HTTPS URL with a trusted certificate (e.g., \texttt{https://abc123.ngrok-free.app}) - \item Use this URL in the .yaml configuration file under the 'external-url' field. -\end{enumerate} - -\textbf{Note:} ngrok free tier URLs can change with each session. - -\subsection{Option 2: Local Network with Valid Certificate} - -A more cumbersome approach, if running the verifier on the same network as the Swiyu wallet: - -\begin{enumerate} - \item Obtain a valid TLS/SSL certificate (e.g. from a trusted Certificate Authority). - \item Configure the Generic Verifier application to use the certificate. -\end{enumerate} - -\end{document} - diff --git a/documentation/sequence_diagrams/swiyu_taler_sequence_diagram.txt b/documentation/sequence_diagrams/swiyu_taler_sequence_diagram.txt @@ -42,9 +42,10 @@ sequenceDiagram Kych oauth2 Gateway ->> SwiyuVerifier: GET /management/api/verifications/{verification_id} SwiyuVerifier -->> Kych oauth2 Gateway: {status: SUCCESS/FAILED,\nwallet_response} - note over Browser,Kych oauth2 Gateway: Browser poll detects completion + note over Browser,Kych oauth2 Gateway: /authorize page detects completion and redirects Browser ->> Kych oauth2 Gateway: GET /status/{verification_id}\n?state={state} Kych oauth2 Gateway -->> Browser: {status: "verified"} + Browser ->> Browser: /authorize JS redirects to /finalize Browser ->> Kych oauth2 Gateway: GET /finalize/{verification_id}\n?state={state} Kych oauth2 Gateway -->> Browser: HTTP 302 Redirect\nLocation: {redirect_uri}?code={auth_code}&state={state} Browser ->> Exchange: GET {redirect_uri}\n?code={auth_code}\n&state={state} @@ -57,4 +58,3 @@ sequenceDiagram Exchange -->> TalerWallet: Notify success TalerWallet ->> Exchange: Retry KYC-requiring original operation - diff --git a/documentation/taler-docs/README b/documentation/taler-docs/README @@ -0,0 +1,110 @@ +Kych Documentation for GNU Taler Docs +====================================== + +This directory contains reStructuredText documentation files for Kych +that are intended to be integrated into the GNU Taler documentation +(https://git.taler.net/docs.git). + +Files +----- + + taler-kych-manual.rst - Kych Operator Manual + core/api-kych.rst - Kych OAuth2 Gateway REST API specification + manpages/kych-client-management.1.rst - Man page for kych-client-management + manpages/kych-oauth2-gateway.1.rst - Man page for kych-oauth2-gateway + manpages/kych.conf.5.rst - Man page for kych.conf configuration + images/kych_overview.jpg - Architecture overview diagram + images/swiyu_taler_sequence_diagram.png - Sequence diagram + +Website Locations +----------------- + +After building, the files will be available at: + + taler-kych-manual.rst + -> For Exchange Operators > 4. Kych Operator Manual + -> URL: /taler-kych-manual.html + + core/api-kych.rst + -> For Developers > API Specification > 17.9. Kych OAuth2 Gateway RESTful API + -> URL: /core/api-kych.html + + manpages/kych-client-management.1.rst + -> For System Administrators > UNIX Man Pages > kych-client-management(1) + -> URL: /manpages/kych-client-management.1.html + + manpages/kych-oauth2-gateway.1.rst + -> For System Administrators > UNIX Man Pages > kych-oauth2-gateway(1) + -> URL: /manpages/kych-oauth2-gateway.1.html + + manpages/kych.conf.5.rst + -> For System Administrators > UNIX Man Pages > kych.conf(5) + -> URL: /manpages/kych.conf.5.html + +Building the Documentation +-------------------------- + +1. Clone the taler-docs repository: + + git clone https://git.taler.net/docs.git taler-docs + cd taler-docs + +2. Create a Python virtual environment and install dependencies: + + python3 -m venv .venv + source .venv/bin/activate + pip install sphinx recommonmark sphinx-book-theme sphinxcontrib-httpdomain setuptools + +3. Install graphviz (macOS): + + brew install graphviz + + Or on Debian/Ubuntu: + + apt install graphviz python3-sphinx python3-recommonmark python3-sphinx-book-theme + +4. Copy or symlink the Kych documentation files into taler-docs: + + # From the taler-docs directory: + cp -r /path/to/kych/documentation/taler-docs/* . + + Or create symlinks for development: + + ln -s /path/to/kych/documentation/taler-docs/taler-kych-manual.rst . + ln -s /path/to/kych/documentation/taler-docs/core/api-kych.rst core/ + ln -s /path/to/kych/documentation/taler-docs/manpages/*.rst manpages/ + ln -s /path/to/kych/documentation/taler-docs/images/* images/ + +5. Add the files to the toctree in index.rst (under "For Exchange Operators"): + + taler-kych-manual + + And in core/index.rst (after api-challenger): + + api-kych + +6. Build the HTML documentation: + + source .venv/bin/activate + make html + +7. View the documentation: + + open _build/html/index.html + + Or navigate directly to: + + open _build/html/taler-kych-manual.html + +Building Man Pages +------------------ + +To build man pages: + + make man + +View them with: + + man ./_build/man/kych-oauth2-gateway.1 + man ./_build/man/kych-client-management.1 + man ./_build/man/kych.conf.5 diff --git a/documentation/taler-docs/core/api-kych.rst b/documentation/taler-docs/core/api-kych.rst @@ -0,0 +1,607 @@ +.. + This file is part of GNU TALER. + Copyright (C) 2024, 2025 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 2.1, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + +.. _kych-api: + +=============================== +Kych OAuth2 Gateway RESTful API +=============================== + +The Kych OAuth2 Gateway provides OAuth 2.0 authorization using OID4VP +(OpenID for Verifiable Presentations) with the Swiyu Verifier. It allows +OAuth 2.0 clients (such as a Taler exchange) to verify user identity via +SD-JWT Verifiable Credentials stored in the user's Swiyu Wallet. + +The high-level flow is: + +1. An OAuth 2.0 client is registered with Kych (via configuration file or CLI tool). + +2. When the client needs to verify a user's identity, it calls ``/setup/$CLIENT_ID`` + with its client secret to obtain a ``nonce``. + +3. The client redirects the user-agent to ``/authorize/$NONCE`` with OAuth 2.0 + parameters (``response_type``, ``client_id``, ``redirect_uri``, ``state``, ``scope``). + +4. Kych initiates a verification request with the Swiyu Verifier and returns + a ``verification_url`` (QR code URL) for the user to scan with their Swiyu Wallet. + +5. The user scans the QR code and presents their verifiable credential to the + Swiyu Verifier. + +6. Upon successful verification, Swiyu Verifier sends a webhook notification to + Kych's ``/notification`` endpoint. + +7. The client polls ``/status/$VERIFICATION_ID`` or the user calls + ``/finalize/$VERIFICATION_ID`` to be redirected back to the client with an + authorization code. + +8. The client exchanges the authorization code for an access token via ``/token``. + +9. The client retrieves the verified identity claims via ``/info``. + +.. contents:: Table of Contents + :local: + + +.. _kych-config: + +----------------------- +Receiving Configuration +----------------------- + +.. http:get:: /config + + Returns the public configuration of the Kych service, including supported + verifiable credential types and available claims. Clients can use this + endpoint to discover which claims they can request during authorization. + + This endpoint does not require authentication and can be used for health + checks and service discovery. + + **Response:** + + :http:statuscode:`200 OK`: + The service is operational. Returns a `KychConfigResponse` containing + the service configuration. + + .. ts:def:: KychConfigResponse + + interface KychConfigResponse { + // Service identifier. Always "kych-oauth2-gateway". + name: "kych-oauth2-gateway"; + + // Semantic version of the Kych service (e.g., "1.0.0"). + version: string; + + // Health status indicator. "healthy" indicates the service is + // ready to accept requests. + status: "healthy"; + + // Verifiable credential type identifier configured for this + // Kych instance. For Swiss Beta ID, this is "betaid-sdjwt". + vc_type: string; + + // Credential format. SD-JWT credentials use "vc+sd-jwt". + vc_format: string; + + // List of cryptographic signature algorithms accepted for + // credential verification (e.g., ["ES256"]). + vc_algorithms: string[]; + + // List of claim names that clients can request via the scope + // parameter. Only claims in this list are valid scope values. + // Examples: "family_name", "given_name", "birth_date", "age_over_18". + vc_claims: string[]; + } + + +.. _kych-setup: + +----- +Setup +----- + +.. http:post:: /setup/$CLIENT_ID + + Initiates a new KYC verification session for the specified client. This is + the first step in the verification flow and must be called by the client + (e.g., Taler exchange) before redirecting the user to the authorization + endpoint. + + The client authenticates using HTTP Bearer authentication with its client + secret. Upon success, Kych creates a new session in ``pending`` status and + returns a cryptographically random nonce that identifies this session. + + **Request:** + + :reqheader Authorization: Required. Must be ``Bearer $CLIENT_SECRET`` where + ``$CLIENT_SECRET`` is the secret registered for this client. + + The request body must be empty. + + **Response:** + + :http:statuscode:`200 OK`: + Session created successfully. Returns a `KychSetupResponse` containing + the session nonce. + + :http:statuscode:`401 Unauthorized`: + Authentication failed. Either the ``Authorization`` header is missing, + malformed, or contains an invalid client secret. The client should verify + that it is using the correct secret for the specified ``$CLIENT_ID``. + + :http:statuscode:`404 Not found`: + The ``$CLIENT_ID`` in the URL path does not match any registered client. + The client must be registered via configuration file or CLI before use. + + .. ts:def:: KychSetupResponse + + interface KychSetupResponse { + // Cryptographically random nonce (base64-encoded) that identifies + // this verification session. The client must include this nonce + // in the URL when redirecting the user to /authorize/$NONCE. + // The nonce is single-use and expires after a configured timeout. + nonce: string; + } + + +.. _kych-authorize: + +--------- +Authorize +--------- + +.. http:get:: /authorize/$NONCE + + The OAuth 2.0 authorization endpoint. The client redirects the user's browser + to this endpoint to begin the credential verification process. + + When called, Kych performs the following steps: + + 1. Validates the session identified by ``$NONCE`` exists and is in ``pending`` status. + 2. Validates the OAuth 2.0 parameters (response_type, client_id, redirect_uri, scope). + 3. Creates a verification request with the configured Swiyu Verifier. + 4. Stores the verification details and transitions the session to ``authorized`` status. + 5. Returns either an HTML page with a QR code or a JSON response, depending on + the ``Accept`` header. + + The returned ``verification_url`` should be rendered as a QR code for the user + to scan with their Swiyu Wallet. On mobile devices, the ``verification_deeplink`` + can be used to launch the wallet app directly. + + **Request:** + + :param NONCE: The session nonce obtained from ``/setup``. This is a URL path + parameter, not a query parameter. + + :query response_type: Required. Must be ``code`` for the authorization code + grant flow. Other values are rejected with ``400 Bad Request``. + + :query client_id: Required. The client identifier. Must match the client that + created this session via ``/setup``. Mismatches are rejected. + + :query redirect_uri: Required. The URI where the user will be redirected after + verification completes. Must exactly match the redirect URI registered for + this client in Kych's configuration. Mismatches are rejected for security. + + :query state: Required. An opaque value generated by the client for CSRF + protection. Kych stores this value and includes it in all subsequent + responses and redirects. The client must verify the state matches when + receiving the callback to prevent cross-site request forgery attacks. + + :query scope: Required. Space-delimited list of credential claims to request + from the user's verifiable credential. Each claim must be in the list + returned by ``/config``. Example: ``family_name given_name age_over_18``. + The user will be asked to consent to disclosing these specific claims. + + **Response:** + + :http:statuscode:`200 OK`: + Verification request created successfully. If the ``Accept`` header includes + ``text/html``, returns an HTML page containing a QR code and JavaScript that + polls the status endpoint. Otherwise, returns a `KychAuthorizeResponse` JSON + object containing the verification URL. + + :http:statuscode:`400 Bad Request`: + One or more request parameters are invalid: + + - ``response_type`` is not ``code`` + - ``redirect_uri`` does not match the registered URI for this client + - ``scope`` contains claims not in the allowed list + - Required parameters are missing + + :http:statuscode:`404 Not found`: + No session exists for the provided ``$NONCE``. The nonce may have never + existed, or it may have already been used (nonces are single-use). + + :http:statuscode:`409 Conflict`: + The session exists but is not in ``pending`` status. This occurs if + ``/authorize`` is called multiple times for the same nonce, or if the + session has already progressed to a later state. + + :http:statuscode:`410 Gone`: + The session has expired. Sessions have a limited lifetime configured on + the server. The client should call ``/setup`` to create a new session. + + :http:statuscode:`502 Bad Gateway`: + Kych failed to communicate with the Swiyu Verifier when creating the + verification request. This may indicate network issues or verifier + unavailability. The client may retry after a delay. + + .. ts:def:: KychAuthorizeResponse + + interface KychAuthorizeResponse { + // UUID assigned by the Swiyu Verifier to identify this verification + // request. Used in the /status and /finalize endpoint URLs. + verificationId: string; + + // URL that encodes the OID4VP verification request. This URL should + // be rendered as a QR code for the user to scan with their Swiyu + // Wallet. The wallet will retrieve the presentation request from + // the Swiyu Verifier using this URL. + verification_url: string; + + // Deep link URL for mobile devices. When opened on a device with + // the Swiyu Wallet installed, this launches the wallet app directly + // instead of requiring QR code scanning. Only present if the Swiyu + // Verifier provides it. + verification_deeplink?: string; + + // The state parameter echoed back unchanged. The client should + // verify this matches the state it sent to detect CSRF attacks. + state: string; + } + + +.. _kych-status: + +------ +Status +------ + +.. http:get:: /status/$VERIFICATION_ID + + Polls the current status of a verification request. Clients (or the browser + JavaScript on the authorize page) use this endpoint to detect when the user + has completed the verification process. + + The ``state`` parameter is required and must match the state from the original + authorization request. This prevents unauthorized parties from polling + verification status. + + **Request:** + + :param VERIFICATION_ID: The verification ID returned by ``/authorize``. + + :query state: Required. The state parameter from the original authorization + request. Must match exactly. This provides CSRF protection and prevents + unauthorized status polling. + + **Response:** + + :http:statuscode:`200 OK`: + Returns a `KychStatusResponse` containing the current verification status. + + :http:statuscode:`403 Forbidden`: + The ``state`` parameter does not match the state associated with this + verification. This may indicate a CSRF attack or that the wrong state + was provided. + + :http:statuscode:`404 Not found`: + No verification exists with the given ``$VERIFICATION_ID``. The ID may + be invalid or the verification may have been deleted after expiration. + + .. ts:def:: KychStatusResponse + + interface KychStatusResponse { + // Current status of the verification. Possible values: + // + // - "pending": Session created but /authorize not yet called. + // (Normally not seen via /status since /authorize must be + // called first to get the verification_id.) + // + // - "authorized": User has been shown the QR code but has not + // yet scanned it or completed verification in their wallet. + // The client should continue polling. + // + // - "verified": The user's credential has been successfully + // verified by the Swiyu Verifier. The client can now redirect + // the user to /finalize to obtain the authorization code. + // + // - "failed": Verification failed. This may occur if the user + // declined consent, presented an invalid credential, or the + // credential issuer is not trusted. + // + // - "expired": The verification session timed out before the + // user completed verification. The client should start a + // new session via /setup. + // + // - "completed": An access token has already been issued for + // this verification. The flow is complete. + status: "pending" | "authorized" | "verified" | "failed" | "expired" | "completed"; + } + + +.. _kych-finalize: + +-------- +Finalize +-------- + +.. http:get:: /finalize/$VERIFICATION_ID + + Completes the authorization flow by redirecting the user back to the client + with an OAuth 2.0 authorization code. This endpoint should only be called + after polling ``/status`` returns ``verified``. + + When called, Kych: + + 1. Validates the session is in ``verified`` status. + 2. Generates a cryptographically random authorization code. + 3. Stores the code with a short expiration time (configurable, default 10 minutes). + 4. Redirects the user's browser to the client's registered ``redirect_uri`` + with the authorization code and state as query parameters. + + The authorization code is single-use. The client must exchange it for an + access token at the ``/token`` endpoint before it expires. + + **Request:** + + :param VERIFICATION_ID: The verification ID returned by ``/authorize``. + + :query state: Required. The state parameter from the original authorization + request. Must match exactly for CSRF protection. + + **Response:** + + :http:statuscode:`302 Found`: + Redirects to the client's ``redirect_uri`` with query parameters: + + - ``code``: The authorization code to exchange for an access token. + - ``state``: The state parameter, echoed back unchanged. + + Example redirect: ``https://client.example.com/callback?code=abc123&state=xyz789`` + + :http:statuscode:`400 Bad Request`: + The verification is not in ``verified`` status. This occurs if: + + - The user has not completed verification yet (status is ``authorized``) + - Verification failed (status is ``failed``) + - A token was already issued (status is ``completed``) + + :http:statuscode:`403 Forbidden`: + The ``state`` parameter does not match. + + :http:statuscode:`404 Not found`: + No verification exists with the given ``$VERIFICATION_ID``. + + +.. _kych-token: + +----- +Token +----- + +.. http:post:: /token + + Exchanges an authorization code for an access token. This is the standard + OAuth 2.0 token endpoint implementing the authorization code grant. + + The client authenticates by including its ``client_id`` and ``client_secret`` + in the request body (not via HTTP Basic authentication). The ``redirect_uri`` + must exactly match the one used in the original authorization request. + + Authorization codes are single-use. Once exchanged for a token, the code + is invalidated and cannot be used again. Codes also expire after a short + time (configurable, default 10 minutes). + + **Request:** + + :reqheader Content-Type: Must be ``application/x-www-form-urlencoded``. + + The request body contains the following form parameters: + + .. ts:def:: KychTokenRequest + + interface KychTokenRequest { + // The OAuth 2.0 grant type. Must be "authorization_code". + grant_type: "authorization_code"; + + // The authorization code received from the /finalize redirect. + // This code is single-use and expires after a short time. + code: string; + + // The client identifier. Must match the client that initiated + // the authorization flow. + client_id: string; + + // The client secret for authentication. Kych verifies this + // against the stored bcrypt hash. + client_secret: string; + + // The redirect URI. Must exactly match the redirect_uri used + // in the original /authorize request. This prevents authorization + // code injection attacks. + redirect_uri: string; + } + + **Response:** + + :http:statuscode:`200 OK`: + Token issued successfully. Returns a `KychTokenResponse` containing + the access token. The session status is updated to ``completed``. + + :http:statuscode:`400 Bad Request`: + The request is invalid. Possible causes: + + - ``grant_type`` is not ``authorization_code`` + - ``code`` is missing, invalid, expired, or already used + - ``redirect_uri`` does not match the original request + - Required parameters are missing + + :http:statuscode:`401 Unauthorized`: + Client authentication failed. Either ``client_id`` does not exist or + ``client_secret`` does not match the registered secret. + + .. ts:def:: KychTokenResponse + + interface KychTokenResponse { + // The access token. Use this as a Bearer token in the + // Authorization header when calling /info. + access_token: string; + + // The token type. Always "Bearer". + token_type: "Bearer"; + + // Token validity period in seconds. The token cannot be used + // after this time. Typically 3600 (1 hour). + expires_in: number; + } + + +.. _kych-info: + +---- +Info +---- + +.. http:get:: /info + + Retrieves the verified identity claims using an access token. This endpoint + is analogous to the OAuth 2.0 UserInfo endpoint but returns verified + credential claims instead of user profile information. + + The response contains only the claims that were: + + 1. Requested in the ``scope`` parameter during authorization. + 2. Successfully disclosed by the user from their verifiable credential. + + The access token is validated on each request. Expired or revoked tokens + are rejected. + + **Request:** + + :reqheader Authorization: Required. Must be ``Bearer $ACCESS_TOKEN`` where + ``$ACCESS_TOKEN`` is the token received from ``/token``. + + **Response:** + + :http:statuscode:`200 OK`: + Returns a `KychInfoResponse` containing the verified claims. + + :http:statuscode:`401 Unauthorized`: + The access token is missing, malformed, expired, or has been revoked. + The client should obtain a new token by starting a new verification flow. + + .. ts:def:: KychInfoResponse + + interface KychInfoResponse { + // The verified credential claims as key-value pairs. Only claims + // that were requested and disclosed are included. + // + // Example response for scope "family_name given_name age_over_18": + // { + // "family_name": "Muster", + // "given_name": "Max", + // "age_over_18": true + // } + // + // Claim types vary: + // - String claims: family_name, given_name, birth_place, nationality, etc. + // - Boolean claims: age_over_16, age_over_18, age_over_65 + // - Date claims: birth_date, issuance_date, expiry_date (ISO 8601 format) + // - Binary claims: portrait (base64-encoded image data) + [claim: string]: string | boolean | number | object; + } + + +.. _kych-notification: + +------------ +Notification +------------ + +.. http:post:: /notification + + Webhook endpoint for receiving asynchronous notifications from the Swiyu + Verifier. The verifier calls this endpoint when a verification request + changes state, typically when the user presents their credential. + + When a notification is received, Kych: + + 1. Looks up the verification session by ``verification_id``. + 2. Queries the Swiyu Verifier's management API for the verification result. + 3. If successful, extracts the disclosed claims and updates the session + to ``verified`` status. + 4. If failed, updates the session to ``failed`` status. + + This endpoint always returns ``200 OK`` to acknowledge receipt, regardless + of whether processing succeeded. Errors are logged internally. This prevents + the verifier from retrying notifications that cannot be processed. + + **Request:** + + :reqheader Content-Type: Should be ``application/json``. + + .. ts:def:: KychNotificationRequest + + interface KychNotificationRequest { + // UUID of the verification request as assigned by the Swiyu + // Verifier. Kych uses this to look up the corresponding session. + verification_id: string; + + // ISO 8601 timestamp indicating when the verification state + // changed. Used for logging and debugging. + timestamp: string; + } + + **Response:** + + :http:statuscode:`200 OK`: + Notification acknowledged. The response body is empty. This status is + returned regardless of processing outcome to prevent retries. + + +.. _kych-errors: + +------ +Errors +------ + +All error responses use the following format: + +.. ts:def:: KychErrorResponse + + interface KychErrorResponse { + // Error code identifier + error: string; + } + +Common error codes: + +- ``unauthorized``: Missing or invalid authentication credentials. +- ``invalid_request``: Malformed request parameters. +- ``invalid_redirect_uri``: The redirect URI does not match the registered value. +- ``invalid_scope``: Requested scopes are not allowed. +- ``invalid_grant``: Authorization code is invalid, expired, or already used. +- ``invalid_client``: Client authentication failed. +- ``invalid_token``: Access token is invalid, expired, or revoked. +- ``invalid_state``: The state parameter does not match. +- ``session_not_found``: The session or verification was not found. +- ``session_expired``: The session has expired. +- ``not_verified``: The session has not been verified yet. +- ``verifier_unavailable``: Cannot communicate with the Swiyu Verifier. +- ``verifier_error``: The Swiyu Verifier returned an error. +- ``internal_error``: An internal server error occurred. diff --git a/documentation/kych_architecture.jpg b/documentation/taler-docs/images/kych_overview.jpg Binary files differ. diff --git a/documentation/taler-docs/images/swiyu_taler_sequence_diagram.png b/documentation/taler-docs/images/swiyu_taler_sequence_diagram.png Binary files differ. diff --git a/documentation/taler-docs/kych.conf.5.rst b/documentation/taler-docs/kych.conf.5.rst @@ -0,0 +1,206 @@ +kych.conf(5) +############ + +.. only:: html + + Name + ==== + + **kych.conf** - Kych OAuth2 Gateway configuration file + + +Description +=========== + +The Kych OAuth2 Gateway uses an INI-style configuration file. The configuration +defines server binding options, database connection, cryptographic parameters, +verifiable credential settings, and OAuth2 client configurations. + +A configuration file may include another, by using the ``@INLINE@`` directive, +for example, in ``main.conf``, you could write ``@INLINE@ sub.conf`` to +include the entirety of ``sub.conf`` at that point in ``main.conf``. + + +GLOBAL OPTIONS +-------------- + +The following options are from the ``[kych-oauth2-gateway]`` section. + + +Server Binding +^^^^^^^^^^^^^^ + +The server can listen on either a TCP socket or a Unix domain socket, but not both. + +HOST + IP address or hostname to bind the TCP server to, e.g. ``127.0.0.1`` or ``0.0.0.0``. + Required when using TCP mode. Must be specified together with ``PORT``. + +PORT + TCP port number to listen on, e.g. ``8080``. + Required when using TCP mode. Must be specified together with ``HOST``. + +UNIXPATH + Path to the Unix domain socket file, e.g. ``/run/kych/kych.sock``. + Required when using Unix socket mode. Cannot be used together with ``HOST``/``PORT``. + +UNIXPATH_MODE + File permissions for the Unix domain socket in octal notation. + Default: ``666``. + Only used when ``UNIXPATH`` is set. + + +Database +^^^^^^^^ + +DATABASE + PostgreSQL connection string for the database. + Required. Example: ``postgres://user:password@localhost/kych``. + + +Cryptographic Parameters +^^^^^^^^^^^^^^^^^^^^^^^^ + +NONCE_BYTES + Number of random bytes to generate for nonces. + Required. Recommended value: ``32``. + +TOKEN_BYTES + Number of random bytes to generate for access tokens. + Required. Recommended value: ``32``. + +AUTH_CODE_BYTES + Number of random bytes to generate for authorization codes. + Required. Recommended value: ``32``. + +AUTH_CODE_TTL_MINUTES + Validity period for authorization codes in minutes. + Default: ``10``. + + +Verifiable Credential Configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +These options define the verifiable credential type that Kych will request +from the Swiyu Verifier. + +VC_TYPE + The type identifier of the verifiable credential. + Required. Example: ``betaid-sdjwt``. + +VC_FORMAT + The format of the verifiable credential. + Required. Example: ``vc+sd-jwt``. + +VC_ALGORITHMS + List of acceptable cryptographic algorithms for credential verification. + Required. Format is a bracketed comma-separated list. + Example: ``{ES256}`` or ``{ES256, ES384}``. + +VC_CLAIMS + The complete set of claim names that exist in the verifiable credential type. + This defines which claims are valid and can be requested by clients via the + ``scope`` parameter. The gateway validates that all requested claims are in + this set. Required. Format is a bracketed comma-separated list. + Example: ``{family_name, given_name, birth_date, age_over_18}``. + + +Scope Restrictions +^^^^^^^^^^^^^^^^^^ + +ALLOWED_SCOPES + Optional policy restriction on which claims clients may request. If set, + only the listed claims can be requested, even if more claims are defined + in ``VC_CLAIMS``. If not set, clients may request any claim from ``VC_CLAIMS``. + Use this to limit what data clients can access without changing the credential + configuration. Format is a bracketed comma-separated list. + Example: ``{family_name, age_over_18}``. + + +CLIENT SECTIONS +--------------- + +Each OAuth2 client is configured in a separate section with a name starting with +``client_``, for example ``[client_merchant]`` or ``[client_exchange]``. + +CLIENT_ID + Unique identifier for this OAuth2 client. + Required. + +CLIENT_SECRET + Secret key for client authentication. + Required. + +VERIFIER_URL + Base URL of the Swiyu Verifier service that this client will use. + Required. Example: ``https://verifier.swiyu.admin.ch``. + +VERIFIER_MANAGEMENT_API_PATH + Path to the verifier's management API endpoint. + Default: ``/management/api/verifications``. + +REDIRECT_URI + OAuth2 callback URL where the authorization response will be sent. + Required. Must match the redirect URI registered with the client application. + Example: ``https://merchant.example.com/kyc/callback``. + +ACCEPTED_ISSUER_DIDS + Optional list of trusted issuer DIDs for verifiable credentials. + Format is a bracketed comma-separated list. + If not specified, credentials from any issuer are accepted. + Example: ``{did:tdw:issuer1, did:tdw:issuer2}``. + + +EXAMPLE CONFIGURATION +===================== + +:: + + [kych-oauth2-gateway] + # TCP binding (use either TCP or Unix socket, not both) + #HOST = 127.0.0.1 + #PORT = 8080 + + # Unix socket binding + UNIXPATH = /run/kych/kych.sock + UNIXPATH_MODE = 666 + + # Database connection + DATABASE = postgres://kych:secret@localhost/kych + + # Cryptographic parameters + NONCE_BYTES = 32 + TOKEN_BYTES = 32 + AUTH_CODE_BYTES = 32 + AUTH_CODE_TTL_MINUTES = 10 + + # Optional scope restriction + #ALLOWED_SCOPES = {family_name, given_name, birth_date} + + # Verifiable Credential configuration + VC_TYPE = betaid-sdjwt + VC_FORMAT = vc+sd-jwt + VC_ALGORITHMS = {ES256} + VC_CLAIMS = {family_name, given_name, birth_date, nationality} + + # Client configuration + [client_merchant] + CLIENT_ID = merchant_prod_01 + CLIENT_SECRET = supersecretkey + VERIFIER_URL = https://verifier.swiyu.admin.ch + VERIFIER_MANAGEMENT_API_PATH = /management/api/verifications + REDIRECT_URI = https://merchant.example.com/kyc/callback + ACCEPTED_ISSUER_DIDS = {did:tdw:trusted_issuer} + + +SEE ALSO +======== + +kych-oauth2-gateway(1), kych-client-management(1). + + +BUGS +==== + +Report bugs by using https://bugs.taler.net/ or by sending electronic +mail to <taler@gnu.org>. diff --git a/documentation/taler-docs/manpages/kych-client-management.1.rst b/documentation/taler-docs/manpages/kych-client-management.1.rst @@ -0,0 +1,127 @@ +kych-client-management(1) +######################### + +Name +==== + +**kych-client-management** - Manage OAuth2 Gateway clients for Kych + +Synopsis +======== + +**kych-client-management** [**-c** *CONFIG* | **--config=**\ \ *CONFIG*] *COMMAND* [*OPTIONS*] + +Description +=========== + +**kych-client-management** is a command-line tool for managing OAuth2 clients +in the Kych OAuth2 Gateway. It allows administrators to create, update, delete, +list, and synchronize client configurations stored in the database. + +Global Options +============== + +**-c** *CONFIG* \| **--config=**\ \ *CONFIG* + Use the configuration file *CONFIG*. This option is required for all commands. + +Commands +======== + +list +---- + +List all registered OAuth2 clients. + +**kych-client-management** **-c** *CONFIG* **list** + +show +---- + +Show details of a specific OAuth2 client. + +**kych-client-management** **-c** *CONFIG* **show** *CLIENT_ID* + +*CLIENT_ID* + The identifier of the client to display. + +create +------ + +Create a new OAuth2 client. + +**kych-client-management** **-c** *CONFIG* **create** [*OPTIONS*] + +**--client-id=**\ \ *CLIENT_ID* + The unique identifier for the new client. Required. + +**--secret=**\ \ *SECRET* + The client secret for authentication. Required. + +**--verifier-url=**\ \ *URL* + The URL of the verifier service. Required. + +**--verifier-api-path=**\ \ *PATH* + The API path on the verifier for verifications. + Default: ``/management/api/verifications`` + +**--redirect-uri=**\ \ *URI* + The OAuth2 redirect URI for this client. Required. + +**--accepted-issuer-dids=**\ \ *DIDS* + Comma-separated list of accepted issuer DIDs. + +update +------ + +Update an existing OAuth2 client. At least one option must be provided. + +**kych-client-management** **-c** *CONFIG* **update** *CLIENT_ID* [*OPTIONS*] + +*CLIENT_ID* + The identifier of the client to update. + +**--verifier-url=**\ \ *URL* + Update the verifier service URL. + +**--verifier-api-path=**\ \ *PATH* + Update the verifier API path. + +**--redirect-uri=**\ \ *URI* + Update the OAuth2 redirect URI. + +**--accepted-issuer-dids=**\ \ *DIDS* + Update the accepted issuer DIDs. + +delete +------ + +Delete an OAuth2 client. + +**kych-client-management** **-c** *CONFIG* **delete** [*OPTIONS*] *CLIENT_ID* + +*CLIENT_ID* + The identifier of the client to delete. + +**-y** \| **--yes** + Skip the confirmation prompt. + +sync +---- + +Synchronize clients from the configuration file to the database. + +**kych-client-management** **-c** *CONFIG* **sync** [*OPTIONS*] + +**--prune** + Remove clients from the database that are not present in the configuration file. + +See Also +======== + +kych.conf(5), kych-oauth2-gateway(1) + +Bugs +==== + +Report bugs by using https://bugs.taler.net/ or by sending electronic +mail to <taler@gnu.org>. diff --git a/documentation/taler-docs/manpages/kych-oauth2-gateway.1.rst b/documentation/taler-docs/manpages/kych-oauth2-gateway.1.rst @@ -0,0 +1,71 @@ +kych-oauth2-gateway(1) +###################### + +.. only:: html + + Name + ==== + + **kych-oauth2-gateway** - HTTP server providing OAuth 2.0 endpoints for KYC verification + + +Synopsis +======== + +**kych-oauth2-gateway** +[**-c** *FILE* | **--config=**\ ‌\ *FILE*] +[**-L** *LEVEL* | **--log-level=**\ \ *LEVEL*] +[**-h** | **--help**] +[**-V** | **--version**] + + +Description +=========== + +**kych-oauth2-gateway** is an HTTP server that provides OAuth 2.0 endpoints +for KYC (Know Your Customer) verification using OID4VP (OpenID for Verifiable +Presentations) with the Swiyu Verifier. + +Its options are as follows: + +**-c** *FILE* \| **--config=**\ ‌\ *FILE* + Use the configuration from *FILE*. This option is required. + +**-L** *LEVEL* \| **--log-level=**\ \ *LEVEL* + Set the logging verbosity to *LEVEL*. Valid values are ERROR, WARN, + INFO, DEBUG, and TRACE. Defaults to INFO. + +**-h** \| **--help** + Print short help on options. + +**-V** \| **--version** + Print version information. + + +Examples +======== + +Start the server with a configuration file: + +.. code-block:: shell + + $ kych-oauth2-gateway -c /etc/kych/kych.conf + +Start the server with debug logging enabled: + +.. code-block:: shell + + $ kych-oauth2-gateway -c /etc/kych/kych.conf -L DEBUG + + +See Also +======== + +kych.conf(5), kych-client-management(1). + + +Bugs +==== + +Report bugs by using https://bugs.taler.net or by sending electronic +mail to <taler@gnu.org>. diff --git a/documentation/taler-docs/taler-kych-manual.rst b/documentation/taler-docs/taler-kych-manual.rst @@ -0,0 +1,701 @@ +.. + This file is part of GNU TALER. + + Copyright (C) 2024, 2025 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 2.1, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + + +Kych Operator Manual +#################### + +Introduction +============ + +About Kych +---------- + +Kych is an OAuth 2.0-compatible gateway for KYC (Know Your Customer) verification +using OID4VP (OpenID for Verifiable Presentations) with Swiyu Verifier. +By redirecting a user-agent to a Kych service, a client (such as a Taler exchange) +can have Kych verify the user's identity through verifiable credentials stored +in the user's Swiyu Wallet and obtain the verified identity attributes via +the ``/info`` endpoint. + + +About this manual +----------------- + +This manual targets system administrators who want to install, +operate or integrate a Kych service. To report issues +or learn about known limitations, please check our +`bug tracker <https://bugs.taler.net>`__. + + +Architecture overview +--------------------- + +The following diagram shows the high-level architecture of Kych and its +interactions with other components: + +.. image:: images/kych_overview.jpg + :alt: Kych Architecture Overview + :align: center + +Kych acts as an OAuth 2.0 gateway that orchestrates KYC verification between: + +- **Taler Exchange**: The client that requires KYC verification for users. +- **Kych OAuth2 Gateway**: Manages OAuth 2.0 flows and verification sessions. +- **Swiyu Verifier**: Handles OID4VP verification requests. +- **Swiyu Wallet**: The user's mobile wallet containing verifiable credentials. + +The following sequence diagram illustrates the complete verification flow: + +.. image:: images/swiyu_taler_sequence_diagram.png + :alt: Swiyu-Taler Verification Sequence Diagram + :align: center + +The flow proceeds as follows: + +1. The *resource owner* (user) initiates a KYC-requiring operation with the + *client* (e.g., Taler exchange). + +2. The *client* calls ``POST /setup/{client_id}`` with its client secret to + obtain a ``nonce`` for the verification session. + +3. The *client* redirects the user-agent to ``GET /authorize/{nonce}`` with + OAuth 2.0 parameters (``response_type``, ``client_id``, ``redirect_uri``, + ``state``, ``scope``). + +4. Kych creates a verification request with the Swiyu Verifier and returns + an HTML page with a QR code (or JSON with ``verification_url``). + +5. The user scans the QR code with their Swiyu Wallet, which retrieves the + presentation definition and requests user consent. + +6. Upon user consent, the Swiyu Wallet presents the requested credentials to + the Swiyu Verifier. + +7. The Swiyu Verifier sends a webhook notification to Kych's ``/notification`` + endpoint with the verification result. + +8. The client polls ``GET /status/{verification_id}`` until the status becomes + ``verified``, then redirects to ``GET /finalize/{verification_id}``. + +9. Kych redirects the user to the client's ``redirect_uri`` with an + authorization code. + +10. The client exchanges the authorization code for an access token via + ``POST /token``. + +11. The client retrieves the verified identity claims via ``GET /info`` using + the access token. + + +.. _KychInstallation: + +Installation +============ + +Prerequisites +------------- + +Before installing Kych, ensure you have the following: + +* Rust toolchain (stable, version 1.70 or later) +* PostgreSQL 12 or later +* A Swiyu Verifier instance with API access + + +Building from source +-------------------- + +Clone the Kych repository and build the release binaries: + +.. code-block:: shell-session + + $ git clone https://github.com/example/kych.git + $ cd kych/kych_oauth2_gateway + $ cargo build --release + +The compiled binaries will be available in ``target/release/``: + +* ``kych-oauth2-gateway`` - the main HTTP server +* ``kych-client-management`` - CLI tool for managing clients + + +Database setup +-------------- + +Kych uses PostgreSQL to store client configurations, verification sessions, +authorization codes, and access tokens. + +First, switch to the ``postgres`` user and create a database user and database +for Kych: + +.. code-block:: shell-session + + [root@server]# su - postgres + [postgres@server]# createuser kych + [postgres@server]# createdb -O kych kych + [postgres@server]# exit + +The ``createuser`` command creates a PostgreSQL role named ``kych``. +The ``createdb`` command creates a database named ``kych`` owned by the +``kych`` role (``-O kych``). + +Next, initialize the database schema. Kych uses a versioning system to manage +database migrations. First, install the versioning support, then apply the +schema migration: + +.. code-block:: shell-session + + $ psql -U kych -d kych -f oauth2_gatewaydb/versioning.sql + $ psql -U kych -d kych -f oauth2_gatewaydb/oauth2gw-0001.sql + +The ``versioning.sql`` script installs the ``_v`` schema which tracks applied +database patches. The ``oauth2gw-0001.sql`` script creates the ``oauth2gw`` +schema with the following tables: + +- ``clients``: Registered OAuth 2.0 clients and their configurations. +- ``verification_sessions``: Active and completed verification sessions. +- ``authorization_codes``: OAuth 2.0 authorization codes issued after verification. +- ``access_tokens``: Bearer tokens issued to clients for accessing user data. + +.. note:: + + The SQL migration files are located in the ``oauth2_gatewaydb/`` directory + of the Kych source tree. Adjust the path if you installed Kych to a + different location. + + +Configuration +============= + +Configuration file location +--------------------------- + +Kych reads its configuration from a file in INI format. The default location +is ``/etc/kych/kych.conf``. You can specify an alternative path using the +``--config`` or ``-c`` command-line option. + + +Main configuration section +-------------------------- + +The main configuration is specified in the ``[kych-oauth2-gateway]`` section: + +.. code-block:: ini + :caption: /etc/kych/kych.conf + + [kych-oauth2-gateway] + # Server binding - choose either TCP or Unix socket (not both) + + # For TCP binding: + #HOST = 127.0.0.1 + #PORT = 8080 + + # For Unix socket binding: + UNIXPATH = /run/kych/kych.sock + UNIXPATH_MODE = 666 + + # Database connection string + DATABASE = postgres://kych:password@localhost/kych + + # Cryptographic parameters + NONCE_BYTES = 32 + TOKEN_BYTES = 32 + AUTH_CODE_BYTES = 32 + AUTH_CODE_TTL_MINUTES = 10 + + # Optional: restrict allowed OAuth scopes + #ALLOWED_SCOPES = {family_name, given_name, birth_date} + + +Server binding options +---------------------- + +Kych can listen on either a TCP socket or a Unix domain socket, but not both +simultaneously. For production deployments behind a reverse proxy (recommended), +Unix sockets provide better security by avoiding network exposure. + +**TCP binding:** + +Use TCP binding for development or when Kych must be accessible over the network. + +- ``HOST``: The IP address to bind to. Use ``127.0.0.1`` for localhost-only + access or ``0.0.0.0`` to accept connections on all interfaces. +- ``PORT``: The TCP port to listen on (e.g., ``8080``). + +**Unix socket binding:** + +Use Unix sockets for production deployments behind nginx or another reverse proxy. +This avoids exposing Kych directly to the network. + +- ``UNIXPATH``: Path to the Unix domain socket file (e.g., ``/run/kych/kych.sock``). + Ensure the directory exists and is writable by the Kych process. +- ``UNIXPATH_MODE``: Octal permission mode for the socket file (default: ``666``). + Set to ``660`` if only the reverse proxy user needs access. + + +Database configuration +---------------------- + +Kych requires a PostgreSQL database to persist client registrations, verification +sessions, authorization codes, and access tokens. The connection is specified +using a standard PostgreSQL connection URI. + +- ``DATABASE``: PostgreSQL connection string in the format + ``postgres://user:password@host:port/database``. For local connections, + you can omit the port (defaults to 5432). Example: + ``postgres://kych:secretpassword@localhost/kych`` + +For production deployments, consider using environment variables or a secrets +manager to avoid storing database credentials in plain text configuration files. + + +Cryptographic parameters +------------------------ + +Kych generates cryptographically secure random values for nonces, access tokens, +and authorization codes. These parameters control the size (entropy) and +lifetime of these values. Larger sizes provide more security but result in +longer token strings. + +- ``NONCE_BYTES``: Number of random bytes for session nonces. The nonce is + used in the ``/authorize/{nonce}`` URL to identify the verification session. + Recommended: ``32`` (256 bits of entropy, base64-encoded to ~43 characters). + +- ``TOKEN_BYTES``: Number of random bytes for OAuth 2.0 access tokens. These + tokens are used by clients to access the ``/info`` endpoint. + Recommended: ``32`` (256 bits of entropy). + +- ``AUTH_CODE_BYTES``: Number of random bytes for OAuth 2.0 authorization codes. + These short-lived codes are exchanged for access tokens at the ``/token`` + endpoint. Recommended: ``32`` (256 bits of entropy). + +- ``AUTH_CODE_TTL_MINUTES``: How long authorization codes remain valid before + expiring. Clients must exchange the code for an access token within this + time window. Default: ``10`` minutes. Shorter values are more secure but + may cause issues with slow clients. + + +Verifiable Credential settings +------------------------------ + +These settings define the type of verifiable credential that Kych will request +from the Swiyu Verifier during the OID4VP flow. The configuration must match +the credential type supported by your Swiyu Verifier deployment and the +credentials available in users' Swiyu Wallets. + +.. code-block:: ini + :caption: /etc/kych/kych.conf + + [kych-oauth2-gateway] + VC_TYPE = betaid-sdjwt + VC_FORMAT = vc+sd-jwt + VC_ALGORITHMS = {ES256} + VC_CLAIMS = {family_name, given_name, birth_date, age_over_18} + +- ``VC_TYPE``: The verifiable credential type identifier. This must match + the credential type configured in the Swiyu Verifier. For Swiss Beta ID + credentials, use ``betaid-sdjwt``. + +- ``VC_FORMAT``: The credential format. SD-JWT (Selective Disclosure JWT) + credentials use ``vc+sd-jwt``, which allows users to disclose only the + specific claims requested. + +- ``VC_ALGORITHMS``: Cryptographic signature algorithms accepted for credential + verification, as a bracketed list. The Swiyu ecosystem uses ``{ES256}`` + (ECDSA with P-256 and SHA-256). + +- ``VC_CLAIMS``: The complete set of claims that may be requested from the + credential. Clients specify which of these claims they need via the + ``scope`` parameter in the authorization request. Only claims listed here + can be requested. + +**Available claims for Swiss Beta ID (betaid-sdjwt):** + +The Swiss Beta ID credential supports the following claims: + +*Personal identification:* + +- ``family_name``: Family name (surname) +- ``given_name``: Given name (first name) +- ``birth_date``: Date of birth (ISO 8601 format) +- ``sex``: Gender +- ``portrait``: Photograph of the credential holder + +*Swiss-specific attributes:* + +- ``place_of_origin``: Place of citizenship (Heimatort), a Swiss legal concept +- ``birth_place``: Place of birth +- ``nationality``: Nationality/citizenship +- ``personal_administrative_number``: Swiss social security number (AHV/AVS number) + +*Age verification (selective disclosure):* + +- ``age_over_16``: Boolean indicating if holder is 16 or older +- ``age_over_18``: Boolean indicating if holder is 18 or older +- ``age_over_65``: Boolean indicating if holder is 65 or older +- ``age_birth_year``: Year of birth (for age verification without full date) + +*Document information:* + +- ``document_number``: Identity document number +- ``issuance_date``: When the credential was issued +- ``expiry_date``: When the credential expires +- ``issuing_authority``: Authority that issued the credential +- ``issuing_country``: Country that issued the credential + +*Verification metadata:* + +- ``verification_type``: How the identity was verified (e.g., in-person) +- ``verification_organization``: Organization that performed verification +- ``reference_id_type``: Type of reference identity document +- ``reference_id_expiry_date``: Expiry date of reference document +- ``additional_person_info``: Additional personal information + +For most KYC use cases, requesting ``family_name``, ``given_name``, +``birth_date``, and ``age_over_18`` provides sufficient identity verification +while minimizing data collection. + + +Scope restrictions +------------------ + +Optionally, you can restrict which claims clients are allowed to request, +regardless of what claims are defined in ``VC_CLAIMS``. This provides an +additional policy layer to limit data exposure. + +- ``ALLOWED_SCOPES``: If set, only these claims can be requested by clients. + If not set, clients may request any claim from ``VC_CLAIMS``. Format is + a bracketed comma-separated list. + +For example, to allow clients to only verify age without accessing personal +details: + +.. code-block:: ini + + ALLOWED_SCOPES = {age_over_18, age_over_16} + + +Client Management +================= + +OAuth 2.0 clients (such as Taler exchanges) must be registered with Kych before +they can initiate KYC verification flows. Each client has its own credentials, +redirect URI, and may use a different Swiyu Verifier instance. + +There are two methods to manage clients: + +- **Configuration-based**: Define clients in the configuration file and use the + ``sync`` command to load them into the database. Good for infrastructure-as-code + deployments. + +- **CLI-based**: Use the ``kych-client-management`` tool to create, update, and + delete clients directly in the database. Good for dynamic management. + + +Configuration-based client management +------------------------------------- + +Clients can be defined in the configuration file using ``[client_*]`` sections. +Each section name must start with ``client_`` followed by a unique identifier +(e.g., ``[client_exchange]``, ``[client_staging]``). + +.. code-block:: ini + :caption: /etc/kych/kych.conf + + [client_exchange] + CLIENT_ID = exchange_production + CLIENT_SECRET = secret-token:your-secure-secret-here + VERIFIER_URL = https://swiyu-verifier.example.com + VERIFIER_MANAGEMENT_API_PATH = /management/api/verifications + REDIRECT_URI = https://exchange.example.com/kyc/kych-redirect + ACCEPTED_ISSUER_DIDS = {did:tdw:trusted_issuer_1, did:tdw:trusted_issuer_2} + +**Client configuration options:** + +- ``CLIENT_ID``: Unique identifier that the client uses to authenticate with + Kych. This is passed in the ``client_id`` parameter during OAuth 2.0 flows + and in the ``/setup/{client_id}`` endpoint URL. + +- ``CLIENT_SECRET``: Shared secret for client authentication. The client + provides this as a Bearer token in the ``Authorization`` header when calling + ``/setup``, and in the request body when calling ``/token``. Use the + ``secret-token:`` prefix per RFC 8959 for secrets that should not be logged. + Kych stores the secret as a bcrypt hash in the database. + +- ``VERIFIER_URL``: Base URL of the Swiyu Verifier instance that this client + will use for credential verification. Different clients can use different + verifier instances (e.g., production vs. staging). + +- ``VERIFIER_MANAGEMENT_API_PATH``: Path to the verifier's management API + endpoint for creating verification requests. Default: + ``/management/api/verifications``. Only change this if your Swiyu Verifier + uses a non-standard API path. + +- ``REDIRECT_URI``: The OAuth 2.0 redirect URI where users are sent after + completing verification. This must exactly match the ``redirect_uri`` + parameter provided by the client in authorization requests. For security, + Kych rejects requests with mismatched redirect URIs. + +- ``ACCEPTED_ISSUER_DIDS``: List of trusted credential issuer DIDs (Decentralized + Identifiers) in bracketed format. Only credentials issued by these DIDs will + be accepted. This provides trust anchoring - you specify which issuers you + trust to have properly verified identities. Example: + ``{did:tdw:issuer1, did:tdw:issuer2}``. + + +CLI-based client management +--------------------------- + +The ``kych-client-management`` tool manages clients directly in the database. +All commands require the ``--config`` option to specify the configuration file +(for database connection settings). + +**Listing clients:** + +Display all registered clients: + +.. code-block:: shell-session + + $ kych-client-management --config /etc/kych/kych.conf list + +This shows a summary of all clients including their IDs and verifier URLs. + +**Viewing client details:** + +Show full details for a specific client: + +.. code-block:: shell-session + + $ kych-client-management --config /etc/kych/kych.conf show exchange_prod + +This displays all configuration options for the client, except the secret +(which is stored as a hash). + +**Creating a client:** + +Register a new OAuth 2.0 client: + +.. code-block:: shell-session + + $ kych-client-management --config /etc/kych/kych.conf create \ + --client-id exchange_prod \ + --secret "secret-token:your-secure-secret" \ + --verifier-url https://swiyu-verifier.example.com \ + --redirect-uri https://exchange.example.com/kyc/kych-redirect \ + --accepted-issuer-dids "{did:tdw:trusted_issuer}" + +The ``--client-id``, ``--secret``, ``--verifier-url``, and ``--redirect-uri`` +options are required. The ``--verifier-api-path`` defaults to +``/management/api/verifications`` if not specified. + +**Updating a client:** + +Modify an existing client's configuration: + +.. code-block:: shell-session + + $ kych-client-management --config /etc/kych/kych.conf update exchange_prod \ + --redirect-uri https://new-exchange.example.com/kyc/kych-redirect + +Only the specified options are updated; other settings remain unchanged. + +**Deleting a client:** + +Remove a client from the database: + +.. code-block:: shell-session + + $ kych-client-management --config /etc/kych/kych.conf delete exchange_prod + +You will be prompted for confirmation. Use ``-y`` to skip the prompt: + +.. code-block:: shell-session + + $ kych-client-management --config /etc/kych/kych.conf delete exchange_prod -y + +.. warning:: + + Deleting a client will cascade to all associated sessions and tokens. + +**Synchronizing configuration to database:** + +The ``sync`` command is the bridge between configuration-based and database-based +client management. It reads all ``[client_*]`` sections from the configuration +file and creates or updates the corresponding clients in the database: + +.. code-block:: shell-session + + $ kych-client-management --config /etc/kych/kych.conf sync + +This is useful for infrastructure-as-code workflows where client configuration +is managed in version control and deployed to the database during releases. + +To also remove clients from the database that are no longer defined in the +configuration file, use the ``--prune`` flag: + +.. code-block:: shell-session + + $ kych-client-management --config /etc/kych/kych.conf sync --prune + +.. warning:: + + The ``--prune`` flag will delete clients and all their associated sessions + and tokens. Use with caution in production. + + +Deployment +========== + +systemd service +--------------- + +Create a systemd service file for Kych: + +.. code-block:: ini + :caption: /etc/systemd/system/kych.service + + [Unit] + Description=Kych OAuth2 Gateway + After=network.target postgresql.service + + [Service] + Type=simple + User=kych + Group=kych + ExecStart=/usr/local/bin/kych-oauth2-gateway --config /etc/kych/kych.conf + Restart=always + RestartSec=5 + + [Install] + WantedBy=multi-user.target + +Enable and start the service: + +.. code-block:: shell-session + + [root@server]# systemctl daemon-reload + [root@server]# systemctl enable kych + [root@server]# systemctl start kych + + +Reverse proxy setup +------------------- + +Kych should be deployed behind a reverse proxy that provides TLS termination, +as required by OAuth 2.0. The following example shows an nginx configuration +using a Unix socket: + +.. code-block:: nginx + :caption: /etc/nginx/sites-available/kych + + upstream kych { + server unix:/run/kych/kych.sock; + } + + server { + listen 443 ssl http2; + server_name kych.example.com; + + ssl_certificate /etc/letsencrypt/live/kych.example.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/kych.example.com/privkey.pem; + + location / { + proxy_pass http://kych; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + } + +Enable the site: + +.. code-block:: shell-session + + [root@server]# ln -s /etc/nginx/sites-available/kych /etc/nginx/sites-enabled/kych + [root@server]# nginx -t + [root@server]# systemctl reload nginx + + +Webhook configuration +--------------------- + +Kych receives callbacks from the Swiyu Verifier when a verification request +changes state (e.g., when the user presents their credential). The webhook +endpoint is ``/notification``. + +When configuring the Swiyu Verifier, set the callback URL to: + +:: + + https://kych.example.com/notification + +This endpoint must be accessible from the Swiyu Verifier service. + +.. note:: + + The Swiyu Verifier must be configured to send notifications to the Kych + gateway. Consult the Swiyu Verifier documentation for details on configuring + webhook callbacks. The verifier will POST a JSON payload containing the + ``verification_id`` and ``timestamp`` when a verification completes. + + +Integration with Taler Exchange +=============================== + +To use Kych as a KYC provider for a GNU Taler exchange, configure the +exchange with the following settings: + +.. code-block:: ini + :caption: /etc/taler-exchange/conf.d/exchange-kyc.conf + + [kyc-provider-kych] + LOGIC = oauth2 + PROVIDED_CHECKS = KYCH_IDENTITY + KYC_OAUTH2_AUTHORIZE_URL = https://kych.example.com/authorize + KYC_OAUTH2_TOKEN_URL = https://kych.example.com/token + KYC_OAUTH2_INFO_URL = https://kych.example.com/info + KYC_OAUTH2_CLIENT_ID = exchange_production + KYC_OAUTH2_CLIENT_SECRET = secret-token:your-secure-secret + KYC_OAUTH2_POST_URL = https://kych.example.com + +The exchange will then use Kych for KYC verification when the +``KYCH_IDENTITY`` check is required. + + +OAuth 2.0 endpoints +------------------- + +Kych provides the following OAuth 2.0 endpoints: + +- ``/authorize`` - Authorization endpoint (redirects user to Swiyu Wallet flow) +- ``/token`` - Token endpoint (exchanges authorization code for access token) +- ``/info`` - Info endpoint (returns verified identity claims) + +The flow follows standard OAuth 2.0 authorization code grant: + +1. Client redirects user to ``/authorize`` with ``client_id``, ``redirect_uri``, + ``response_type=code``, and optional ``state`` parameter. + +2. User completes verification via Swiyu Wallet. + +3. User is redirected to the client's ``redirect_uri`` with an authorization + ``code``. + +4. Client exchanges the ``code`` for an ``access_token`` at ``/token``. + +5. Client retrieves user information using the ``access_token`` at ``/info``. diff --git a/kych_oauth2_gateway/README b/kych_oauth2_gateway/README @@ -0,0 +1,142 @@ +KYCH OAuth2 Gateway +=================== + +A Rust service implementing OAuth2 authorization code flow with OpenID4VP +(OID4VP) credential verification. Acts as a bridge between OAuth2 clients +(such as GNU Taler exchanges) and the SWIYU verifier. + +For detailed API documentation and man pages intended for GNU Taler docs, +see ../documentation/taler-docs/. + + +Dependencies +------------ + +Build requirements: + - Rust (edition 2024) + - Cargo + +Runtime requirements: + - PostgreSQL + + +Building +-------- + + cargo build --release + +The build produces two binaries: + - kych-oauth2-gateway Main gateway service + - kych-client-management CLI tool for client management + + +Database Setup +-------------- + +Set up the PostgreSQL database using the scripts in oauth2_gatewaydb/: + + cd oauth2_gatewaydb + ./install_db.sh + +To remove: + + ./uninstall_db.sh + + +Configuration +------------- + +Copy kych.conf.example to kych.conf and configure: + + [kych-oauth2-gateway] + UNIXPATH = /path/to/socket # Unix socket path (or use HOST/PORT) + DATABASE = postgres://... # PostgreSQL connection string + + # Cryptographic parameters + NONCE_BYTES = 32 + TOKEN_BYTES = 32 + AUTH_CODE_BYTES = 32 + AUTH_CODE_TTL_MINUTES = 10 + + # Verifiable Credential settings + VC_TYPE = betaid-sdjwt + VC_FORMAT = vc+sd-jwt + VC_ALGORITHMS = {ES256} + VC_CLAIMS = {family_name, given_name, birth_date, ...} + + # Client configuration (one section per client) + [client_name] + CLIENT_ID = ... + CLIENT_SECRET = ... + VERIFIER_URL = https://verifier.example.com + VERIFIER_MANAGEMENT_API_PATH = /management/api/verifications + REDIRECT_URI = https://client.example.com/callback + ACCEPTED_ISSUER_DIDS = {did:tdw:issuer1, did:tdw:issuer2} + + +Running +------- + + ./target/release/kych-oauth2-gateway -c /path/to/kych.conf + + +API Endpoints +------------- + + GET /config VC configuration (type, format, claims) + POST /setup/{client_id} Initialize verification session + GET /authorize/{nonce} Authorization page with QR code + POST /token Exchange authorization code for token + GET /info Retrieve verified user information + POST /notification Webhook for verifier status updates + GET /status/{verification_id} Check verification status + POST /finalize/{verification_id} Finalize verification + + +Client Management +----------------- + +Use the CLI tool to manage OAuth2 clients: + + ./target/release/kych-client-management --help + + +Testing +------- + + cargo test + +Integration tests are in tests/: + - db_integration.rs Database integration tests + - handlers_integration.rs HTTP handler tests + + +Project Structure +----------------- + + src/ + main.rs Entry point, server initialization + lib.rs Module exports + handlers.rs HTTP endpoint handlers + config.rs Configuration management + models.rs Data structures + state.rs Application state + crypto.rs Cryptographic operations + db/ Database layer + mod.rs Database initialization + clients.rs Client management + authorization_codes.rs Auth code handling + sessions.rs Session management + tokens.rs Token management + + src/bin/ + client_management_cli.rs Client management CLI + + templates/ + authorize.html Authorization page template + + oauth2_gatewaydb/ + install_db.sh Database installation + oauth2gw-0001.sql Schema migration + versioning.sql Version control + drop.sql Cleanup script diff --git a/kych_oauth2_gateway/openapi.yaml b/kych_oauth2_gateway/openapi.yaml @@ -1,313 +0,0 @@ -openapi: 3.0.4 -info: - title: OAuth2 Gateway API - version: '0.0.1' - description: | - The OAuth2 Gateway service orchestrates the Know-Your-Customer (KYC) verification flow - between OAuth2 clients and the Swiyu Verifier, acting as a resource server for the - final Verifiable Credential (VC) proof. - -servers: - - url: https://oauth2gw.example.com - description: OAuth2 Gateway server - -security: - - ClientAuth: [] - -components: - securitySchemes: - ClientAuth: - type: http - scheme: bearer - description: | - Bearer token (Shared Secret) used for server-to-server authentication - of the client identity when calling /setup. - - BearerToken: - type: http - scheme: bearer - description: | - The access_token issued by the OAuth2 Gateway at the /token endpoint, - used to authenticate access to the protected resource at /info. - - schemas: - SetupResponse: - type: object - required: - - nonce - properties: - nonce: - type: string - description: | - The nonce to be used to construct the /authorize URL. - example: '7f3e9d2AXb1c4f6e_5a9d8c7AISFe1A_a4d' - - AuthorizeResponse: - type: object - required: - - verification_id - - verification_url - - state - properties: - verification_id: - type: string - format: uuid - description: | - The unique ID generated by the Swiyu Verifier for the OID4VP session, - used internally by the OAuth2 Gateway. - example: 'd8c1e4f9-2b0e-4a6c-9a3d-5f8b7c2d1e0a' - verification_url: - type: string - format: uri - description: | - The URL that must be opened/scanned (as a QR code) to start the OID4VP flow. - example: 'swiyu://verify?request_uri=https://verifier.example.com/api/v1/request/d8c1e4f9-2b0e-4a6c-9a3d-5f8b7c2d1e0a' - verification_deeplink: - type: string - format: uri - description: | - Optional deeplink URL for mobile wallet applications. - example: 'swiyu://verify?request_uri=https://verifier.example.com/api/v1/request/d8c1e4f9-2b0e-4a6c-9a3d-5f8b7c2d1e0a' - state: - type: string - description: | - The state parameter echoed back from the authorize request for CSRF protection. - example: 'AZS7EDH2VD10GSGG8C1SHNE375DYQKHYJAQK8VJ1117WG' - - NotificationRequest: - type: object - required: - - verification_id - - timestamp - properties: - verification_id: - type: string - format: uuid - description: | - The verification session ID from the Swiyu Verifier. - example: 'd8c1e4f9-2b0e-4a6c-9a3d-5f8b7c2d1e0a' - timestamp: - type: string - format: date-time - description: | - Timestamp when the notification was sent. - example: '2025-12-09T10:30:00Z' - - TokenRequest: - type: object - required: - - grant_type - - code - - client_id - - client_secret - properties: - grant_type: - type: string - enum: [authorization_code] - description: Must be 'authorization_code' for this flow. - code: - type: string - description: The authorization code received from the client notification webhook. - example: '9a4f2e7c8d1b6a3e5f9c8d7e2a1b4c6f' - client_id: - type: string - description: The registered client identifier. - example: 'client_production_01' - client_secret: - type: string - description: The client secret for authentication. - example: 'cs_8f7e6d5c4b3a2f1e9d8c7b6a5f4e3d2c' - - TokenResponse: - type: object - required: - - access_token - - token_type - - expires_in - properties: - access_token: - type: string - description: Token used to authenticate access to the protected /info endpoint. - example: 'at_3d2c1b9a8f7e6d5c4b3a2f1e9d8c7b6a' - token_type: - type: string - enum: [Bearer] - description: Must be "Bearer". - expires_in: - type: integer - description: Amount of time that the access token is valid (in seconds). - example: 3600 - - VerifiableCredential: - type: object - description: The Verifiable Credential (VC) proof object. - properties: - data: - type: object - description: The verified attributes derived from the VC. - example: - vct: 'betaid-sdjwt' - age_over_18: true - iat: 1733741234 - exp: 1765277234 - -paths: - /setup/{clientId}: - post: - summary: Initiate KYC verification session - description: | - The client calls this endpoint to begin a KYC process. It creates a new session and returns a `nonce`. - tags: - - Authorization Flow - security: - - ClientAuth: [] - parameters: - - in: path - name: clientId - schema: - type: string - required: true - description: The registered client identifier. - example: 'client_production_01' - responses: - '200': - description: Session successfully created and nonce returned. - content: - application/json: - schema: - $ref: '#/components/schemas/SetupResponse' - '401': - description: Authentication failed (Invalid or missing client secret). - '404': - description: Client not found. - - /authorize/{nonce}: - get: - summary: Initiate the OID4VP verification flow - description: | - The client constructs a URL to this endpoint using the `nonce` from /setup. - The OAuth2 Gateway initiates the Swiyu verification and returns the verification URL. - tags: - - Authorization Flow - parameters: - - in: path - name: nonce - schema: - type: string - required: true - description: The nonce returned from the /setup endpoint. - example: '7f3e9d2a8b1c4f6e5a9d8c7b3e2f1a4d' - - in: query - name: response_type - schema: - type: string - enum: [code] - required: true - description: Must be 'code' for authorization code flow. - - in: query - name: client_id - schema: - type: string - required: true - description: The registered client identifier. - example: 'client_production_01' - - in: query - name: redirect_uri - schema: - type: string - format: uri - required: true - description: The client redirect URI where the user will be redirected to after verification. - example: 'https://client.example.com/kyc/thank-you' - - in: query - name: state - schema: - type: string - required: true - description: Opaque value used by the client to maintain state between request and callback (CSRF protection). - example: 'payto://iban/CH9300762011623852957' - - in: query - name: scope - schema: - type: string - required: true - description: Space-delimited string of desired attributes to verify. - example: 'age_over_18' - responses: - '200': - description: Verification URL returned. - content: - application/json: - schema: - $ref: '#/components/schemas/AuthorizeResponse' - '404': - description: Nonce not found or session expired. - '410': - description: Session expired. - '409': - description: Invalid session status. - - /notification: - post: - summary: Webhook notification from Swiyu Verifier - description: | - The Swiyu Verifier calls this endpoint to notify the OAuth2 Gateway that - a verification session has been completed. The gateway then notifies the client - via GET request to the redirect_uri with the authorization code. - tags: - - Webhooks - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/NotificationRequest' - responses: - '200': - description: Notification received and processed. - - /token: - post: - summary: Exchange authorization code for access token - description: | - The client calls this endpoint to exchange the authorization code for an access token - after receiving the code via the notification webhook. - tags: - - Authorization Flow - requestBody: - required: true - content: - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/TokenRequest' - responses: - '200': - description: Access token successfully issued. - content: - application/json: - schema: - $ref: '#/components/schemas/TokenResponse' - '400': - description: Invalid request or invalid authorization code. - '401': - description: Client authentication failed. - - /info: - get: - summary: Retrieve the Verifiable Credential proof - description: | - The client calls this endpoint using the access_token to retrieve the - Verifiable Credential proof (protected resource). - tags: - - Resource Retrieval - security: - - BearerToken: [] - responses: - '200': - description: Verifiable Credential proof successfully retrieved. - content: - application/json: - schema: - $ref: '#/components/schemas/VerifiableCredential' - '401': - description: Authentication failed (Invalid or missing access_token). diff --git a/swiyu-verifier/README b/swiyu-verifier/README @@ -0,0 +1,96 @@ +SWIYU Verifier Local Setup +========================== + +Scripts and configuration for running the SWIYU Generic Verifier locally +for development. The verifier is a Java Spring Boot application that +implements OpenID4VP (OID4VP) credential verification. + +The upstream verifier source code is maintained separately. This directory +provides convenience scripts for local development with KYCH. + + +Prerequisites +------------- + + - Java 21 + - Maven 3.x + - PostgreSQL + - SWIYU verifier source code (clone from upstream) + + +Database Setup +-------------- + + ./install_db.sh + +To remove: + + ./uninstall_db.sh + + +Configuration +------------- + +Copy the template and fill in your values: + + cp application-local-dockerless.yml.template application-local-dockerless.yml + +Key configuration options: + + application: + external-url: "" # Public URL of the verifier + client_id: "" # Verifier DID + signing_key: "" # PEM-encoded signing key + client-metadata-file: "classpath:/client_metadata.json" + + spring: + datasource: + url: "jdbc:postgresql://localhost:5432/verifier_db" + username: "verifier_user" + password: "secret" + + webhook: + callback-uri: "" # KYCH gateway notification endpoint + + +Running +------- + +Start the verifier: + + ./run.sh + +Build and run: + + ./run.sh clean + +Run with debugger (port 5005): + + ./run.sh -d + + +API Request Examples +-------------------- + +The api_requests/ directory contains example scripts and payloads: + + post_management_api_verifications.sh + Create a new verification request. + + get_management_api_verifications.sh + Retrieve verification status. + + request_over_18.json + Example verification request using Presentation Exchange. + + +Files +----- + + run.sh Start the verifier + install_db.sh Create PostgreSQL database + uninstall_db.sh Drop PostgreSQL database + application-local-dockerless.yml.template + Configuration template + client_metadata.json OpenID4VP client metadata + api_requests/ Example API requests