kych

OAuth 2.0 API for Swiyu to enable Taler integration of Swiyu for KYC (experimental)
Log | Files | Refs | README | LICENSE

taler-kych-manual.rst (24001B)


      1 ..
      2   This file is part of GNU TALER.
      3 
      4   Copyright (C) 2024, 2025 Taler Systems SA
      5 
      6   TALER is free software; you can redistribute it and/or modify it under the
      7   terms of the GNU Affero General Public License as published by the Free Software
      8   Foundation; either version 2.1, or (at your option) any later version.
      9 
     10   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     11   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     12   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     13 
     14   You should have received a copy of the GNU Affero General Public License along with
     15   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     16 
     17 
     18 KyCH Operator Manual
     19 ####################
     20 
     21 Introduction
     22 ============
     23 
     24 About KyCH
     25 ----------
     26 
     27 KyCH is an OAuth 2.0-compatible gateway for KYC (Know Your Customer) verification
     28 using OID4VP (OpenID for Verifiable Presentations) with Swiyu Verifier.
     29 By redirecting a user-agent to a KyCH service, a client (such as a Taler exchange)
     30 can have KyCH verify the user's identity through verifiable credentials stored
     31 in the user's Swiyu Wallet and obtain the verified identity attributes via
     32 the ``/info`` endpoint.
     33 
     34 
     35 About this manual
     36 -----------------
     37 
     38 This manual targets system administrators who want to install,
     39 operate or integrate a KyCH service.  To report issues
     40 or learn about known limitations, please check our
     41 `bug tracker <https://bugs.taler.net>`__.
     42 
     43 
     44 Architecture overview
     45 ---------------------
     46 
     47 The following diagram shows the high-level architecture of KyCH and its
     48 interactions with other components:
     49 
     50 .. image:: images/kych_overview.jpg
     51    :alt: KyCH Architecture Overview
     52    :align: center
     53 
     54 KyCH acts as an OAuth 2.0 gateway that orchestrates KYC verification between:
     55 
     56 - **Taler Exchange**: The client that requires KYC verification for users.
     57 - **KyCH OAuth2 Gateway**: Manages OAuth 2.0 flows and verification sessions.
     58 - **Swiyu Verifier**: Handles OID4VP verification requests.
     59 - **Swiyu Wallet**: The user's mobile wallet containing verifiable credentials.
     60 
     61 The flow proceeds as follows:
     62 
     63 1. The *resource owner* (user) initiates a KYC-requiring operation with the
     64    *client* (e.g., Taler exchange).
     65 
     66 2. The *client* calls ``POST /setup/{client_id}`` with its client secret to
     67    obtain a ``nonce`` for the verification session.
     68 
     69 3. The *client* redirects the user-agent to ``GET /authorize/{nonce}`` with
     70    OAuth 2.0 parameters (``response_type``, ``client_id``, ``redirect_uri``,
     71    ``state``, ``scope``).
     72 
     73 4. KyCH creates a verification request with the Swiyu Verifier and returns
     74    an HTML page with a QR code (or JSON with ``verification_url``).
     75 
     76 5. The user scans the QR code with their Swiyu Wallet, which retrieves the
     77    presentation definition and requests user consent.
     78 
     79 6. Upon user consent, the Swiyu Wallet presents the requested credentials to
     80    the Swiyu Verifier.
     81 
     82 7. The Swiyu Verifier sends a webhook notification to KyCH's ``/notification``
     83    endpoint with the verification result.
     84 
     85 8. The client polls ``GET /status/{verification_id}`` until the status becomes
     86    ``verified``, then redirects to ``GET /finalize/{verification_id}``.
     87 
     88 9. KyCH redirects the user to the client's ``redirect_uri`` with an
     89    authorization code.
     90 
     91 10. The client exchanges the authorization code for an access token via
     92     ``POST /token``.
     93 
     94 11. The client retrieves the verified identity claims via ``GET /info`` using
     95     the access token.
     96 
     97 
     98 .. _KyCHInstallation:
     99 
    100 Installation
    101 ============
    102 
    103 Prerequisites
    104 -------------
    105 
    106 Before installing KyCH, ensure you have the following:
    107 
    108 * Rust toolchain (stable, version 1.70 or later)
    109 * PostgreSQL 12 or later
    110 * A Swiyu Verifier instance with API access
    111 
    112 
    113 Building from source
    114 --------------------
    115 
    116 Clone the KyCH repository and build the release binaries:
    117 
    118 .. code-block:: shell-session
    119 
    120    $ git clone https://github.com/example/kych.git
    121    $ cd kych/kych_oauth2_gateway
    122    $ cargo build --release
    123 
    124 The compiled binaries will be available in ``target/release/``:
    125 
    126 * ``kych-oauth2-gateway`` - the main HTTP server
    127 * ``kych-client-management`` - CLI tool for managing clients
    128 
    129 
    130 Database setup
    131 --------------
    132 
    133 KyCH uses PostgreSQL to store client configurations, verification sessions,
    134 authorization codes, and access tokens.
    135 
    136 First, switch to the ``postgres`` user and create a database user and database
    137 for KyCH:
    138 
    139 .. code-block:: shell-session
    140 
    141    [root@server]# su - postgres
    142    [postgres@server]# createuser kych
    143    [postgres@server]# createdb -O kych kych
    144    [postgres@server]# exit
    145 
    146 The ``createuser`` command creates a PostgreSQL role named ``kych``.
    147 The ``createdb`` command creates a database named ``kych`` owned by the
    148 ``kych`` role (``-O kych``).
    149 
    150 Next, initialize the database schema. KyCH uses a versioning system to manage
    151 database migrations. First, install the versioning support, then apply the
    152 schema migration:
    153 
    154 .. code-block:: shell-session
    155 
    156    $ psql -U kych -d kych -f oauth2_gatewaydb/versioning.sql
    157    $ psql -U kych -d kych -f oauth2_gatewaydb/oauth2gw-0001.sql
    158 
    159 The ``versioning.sql`` script installs the ``_v`` schema which tracks applied
    160 database patches. The ``oauth2gw-0001.sql`` script creates the ``oauth2gw``
    161 schema with the following tables:
    162 
    163 - ``clients``: Registered OAuth 2.0 clients and their configurations.
    164 - ``verification_sessions``: Active and completed verification sessions.
    165 - ``authorization_codes``: OAuth 2.0 authorization codes issued after verification.
    166 - ``access_tokens``: Bearer tokens issued to clients for accessing user data.
    167 
    168 .. note::
    169 
    170    The SQL migration files are located in the ``oauth2_gatewaydb/`` directory
    171    of the KyCH source tree. Adjust the path if you installed KyCH to a
    172    different location.
    173 
    174 
    175 Configuration
    176 =============
    177 
    178 Configuration file location
    179 ---------------------------
    180 
    181 KyCH reads its configuration from a file in the GNU Taler configuration
    182 format, the same one the rest of the Taler stack uses: INI-like, with
    183 ``@inline@`` includes and ``$VAR`` expansion in paths. The default location is
    184 ``/etc/kych/kych.conf``. You can specify an alternative path using the
    185 ``--config`` or ``-c`` command-line option. See kych.conf(5) for the format
    186 and for the full list of options.
    187 
    188 
    189 Main configuration section
    190 --------------------------
    191 
    192 The main configuration is specified in the ``[kych-oauth2-gateway]`` section:
    193 
    194 .. code-block:: ini
    195    :caption: /etc/kych/kych.conf
    196 
    197    [kych-oauth2-gateway]
    198    # Server binding: unix, tcp or systemd
    199    SERVE = unix
    200 
    201    # For SERVE = unix:
    202    UNIXPATH = /run/kych/kych.sock
    203    UNIXPATH_MODE = 660
    204 
    205    # For SERVE = tcp:
    206    #BIND_TO = 127.0.0.1
    207    #PORT = 8080
    208 
    209    # Database connection string
    210    DATABASE = postgres://kych:password@localhost/kych
    211 
    212    # Cryptographic parameters
    213    NONCE_BYTES = 32
    214    TOKEN_BYTES = 32
    215    AUTH_CODE_BYTES = 32
    216    AUTH_CODE_TTL_MINUTES = 10
    217 
    218    # Optional: restrict allowed OAuth scopes
    219    #ALLOWED_SCOPES = {family_name, given_name, birth_date}
    220 
    221 
    222 Server binding options
    223 ----------------------
    224 
    225 ``SERVE`` selects one of three ways to obtain the listening socket. For
    226 production deployments behind a reverse proxy (recommended), a Unix socket
    227 avoids network exposure altogether.
    228 
    229 **Unix socket binding (SERVE = unix):**
    230 
    231 Use this for production deployments behind nginx or another reverse proxy.
    232 
    233 -  ``UNIXPATH``: Path to the Unix domain socket file (e.g., ``/run/kych/kych.sock``).
    234    Ensure the directory exists and is writable by the KyCH process.
    235 -  ``UNIXPATH_MODE``: Octal permission mode for the socket file. Use ``660``
    236    so that only the reverse proxy user, which shares KyCH's group, can reach it.
    237 
    238 **TCP binding (SERVE = tcp):**
    239 
    240 Use TCP binding for development or when KyCH must be accessible over the network.
    241 
    242 -  ``BIND_TO``: The IP address to bind to. Use ``127.0.0.1`` for localhost-only
    243    access or ``0.0.0.0`` to accept connections on all interfaces.
    244 -  ``PORT``: The TCP port to listen on (e.g., ``8080``).
    245 
    246 **Socket activation (SERVE = systemd):**
    247 
    248 KyCH takes the listening socket from the service manager rather than binding
    249 one, so systemd owns the socket, its permissions and its lifetime, and the
    250 service can start on the first connection. Nothing else needs to be
    251 configured; the Debian package ships a ``kych.socket`` unit for it.
    252 
    253 
    254 Database configuration
    255 ----------------------
    256 
    257 KyCH requires a PostgreSQL database to persist client registrations, verification
    258 sessions, authorization codes, and access tokens. The connection is specified
    259 using a standard PostgreSQL connection URI.
    260 
    261 -  ``DATABASE``: PostgreSQL connection string in the format
    262    ``postgres://user:password@host:port/database``. For local connections,
    263    you can omit the port (defaults to 5432). Example:
    264    ``postgres://kych:secretpassword@localhost/kych``
    265 
    266 For production deployments, consider using environment variables or a secrets
    267 manager to avoid storing database credentials in plain text configuration files.
    268 
    269 
    270 Cryptographic parameters
    271 ------------------------
    272 
    273 KyCH generates cryptographically secure random values for nonces, access tokens,
    274 and authorization codes. These parameters control the size (entropy) and
    275 lifetime of these values. Larger sizes provide more security but result in
    276 longer token strings.
    277 
    278 -  ``NONCE_BYTES``: Number of random bytes for session nonces. The nonce is
    279    used in the ``/authorize/{nonce}`` URL to identify the verification session.
    280    Recommended: ``32`` (256 bits of entropy, base64-encoded to ~43 characters).
    281 
    282 -  ``TOKEN_BYTES``: Number of random bytes for OAuth 2.0 access tokens. These
    283    tokens are used by clients to access the ``/info`` endpoint.
    284    Recommended: ``32`` (256 bits of entropy).
    285 
    286 -  ``AUTH_CODE_BYTES``: Number of random bytes for OAuth 2.0 authorization codes.
    287    These short-lived codes are exchanged for access tokens at the ``/token``
    288    endpoint. Recommended: ``32`` (256 bits of entropy).
    289 
    290 -  ``AUTH_CODE_TTL_MINUTES``: How long authorization codes remain valid before
    291    expiring. Clients must exchange the code for an access token within this
    292    time window. Default: ``10`` minutes. Shorter values are more secure but
    293    may cause issues with slow clients.
    294 
    295 
    296 Verifiable Credential settings
    297 ------------------------------
    298 
    299 These settings define the type of verifiable credential that KyCH will request
    300 from the Swiyu Verifier during the OID4VP flow. The configuration must match
    301 the credential type supported by your Swiyu Verifier deployment and the
    302 credentials available in users' Swiyu Wallets.
    303 
    304 .. code-block:: ini
    305    :caption: /etc/kych/kych.conf
    306 
    307    [kych-oauth2-gateway]
    308    VC_TYPE = betaid-sdjwt
    309    VC_FORMAT = vc+sd-jwt
    310    VC_ALGORITHMS = {ES256}
    311    VC_CLAIMS = {family_name, given_name, birth_date, age_over_18}
    312 
    313 -  ``VC_TYPE``: The verifiable credential type identifier. This must match
    314    the credential type configured in the Swiyu Verifier. For Swiss Beta ID
    315    credentials, use ``betaid-sdjwt``.
    316 
    317 -  ``VC_FORMAT``: The credential format. SD-JWT (Selective Disclosure JWT)
    318    credentials use ``vc+sd-jwt``, which allows users to disclose only the
    319    specific claims requested.
    320 
    321 -  ``VC_ALGORITHMS``: Cryptographic signature algorithms accepted for credential
    322    verification, as a bracketed list. The Swiyu ecosystem uses ``{ES256}``
    323    (ECDSA with P-256 and SHA-256).
    324 
    325 -  ``VC_CLAIMS``: The complete set of claims that may be requested from the
    326    credential. Clients specify which of these claims they need via the
    327    ``scope`` parameter in the authorization request. Only claims listed here
    328    can be requested.
    329 
    330 **Available claims for Swiss Beta ID (betaid-sdjwt):**
    331 
    332 The Swiss Beta ID credential supports the following claims:
    333 
    334 *Personal identification:*
    335 
    336 - ``family_name``: Family name (surname)
    337 - ``given_name``: Given name (first name)
    338 - ``birth_date``: Date of birth (ISO 8601 format)
    339 - ``sex``: Gender
    340 - ``portrait``: Photograph of the credential holder
    341 
    342 *Swiss-specific attributes:*
    343 
    344 - ``place_of_origin``: Place of citizenship (Heimatort), a Swiss legal concept
    345 - ``birth_place``: Place of birth
    346 - ``nationality``: Nationality/citizenship
    347 - ``personal_administrative_number``: Swiss social security number (AHV/AVS number)
    348 
    349 *Age verification (selective disclosure):*
    350 
    351 - ``age_over_16``: Boolean indicating if holder is 16 or older
    352 - ``age_over_18``: Boolean indicating if holder is 18 or older
    353 - ``age_over_65``: Boolean indicating if holder is 65 or older
    354 - ``age_birth_year``: Year of birth (for age verification without full date)
    355 
    356 *Document information:*
    357 
    358 - ``document_number``: Identity document number
    359 - ``issuance_date``: When the credential was issued
    360 - ``expiry_date``: When the credential expires
    361 - ``issuing_authority``: Authority that issued the credential
    362 - ``issuing_country``: Country that issued the credential
    363 
    364 *Verification metadata:*
    365 
    366 - ``verification_type``: How the identity was verified (e.g., in-person)
    367 - ``verification_organization``: Organization that performed verification
    368 - ``reference_id_type``: Type of reference identity document
    369 - ``reference_id_expiry_date``: Expiry date of reference document
    370 - ``additional_person_info``: Additional personal information
    371 
    372 For most KYC use cases, requesting ``family_name``, ``given_name``,
    373 ``birth_date``, and ``age_over_18`` provides sufficient identity verification
    374 while minimizing data collection.
    375 
    376 
    377 Scope restrictions
    378 ------------------
    379 
    380 Optionally, you can restrict which claims clients are allowed to request,
    381 regardless of what claims are defined in ``VC_CLAIMS``. This provides an
    382 additional policy layer to limit data exposure.
    383 
    384 -  ``ALLOWED_SCOPES``: If set, only these claims can be requested by clients.
    385    If not set, clients may request any claim from ``VC_CLAIMS``. Format is
    386    a bracketed comma-separated list.
    387 
    388 For example, to allow clients to only verify age without accessing personal
    389 details:
    390 
    391 .. code-block:: ini
    392 
    393    ALLOWED_SCOPES = {age_over_18, age_over_16}
    394 
    395 
    396 Client Management
    397 =================
    398 
    399 OAuth 2.0 clients (such as Taler exchanges) must be registered with KyCH before
    400 they can initiate KYC verification flows. Each client has its own credentials,
    401 redirect URI, and may use a different Swiyu Verifier instance.
    402 
    403 There are two methods to manage clients:
    404 
    405 - **Configuration-based**: Define clients in the configuration file and use the
    406   ``sync`` command to load them into the database. Good for infrastructure-as-code
    407   deployments.
    408 
    409 - **CLI-based**: Use the ``kych-client-management`` tool to create, update, and
    410   delete clients directly in the database. Good for dynamic management.
    411 
    412 
    413 Configuration-based client management
    414 -------------------------------------
    415 
    416 Clients can be defined in the configuration file using ``[client_*]`` sections.
    417 Each section name must start with ``client_`` followed by a unique identifier
    418 (e.g., ``[client_exchange]``, ``[client_staging]``).
    419 
    420 .. code-block:: ini
    421    :caption: /etc/kych/kych.conf
    422 
    423    [client_exchange]
    424    CLIENT_ID = exchange_production
    425    CLIENT_SECRET = secret-token:your-secure-secret-here
    426    VERIFIER_URL = https://swiyu-verifier.example.com
    427    VERIFIER_MANAGEMENT_API_PATH = /management/api/verifications
    428    REDIRECT_URI = https://exchange.example.com/kyc/kych-redirect
    429    ACCEPTED_ISSUER_DIDS = {did:tdw:trusted_issuer_1, did:tdw:trusted_issuer_2}
    430 
    431 **Client configuration options:**
    432 
    433 -  ``CLIENT_ID``: Unique identifier that the client uses to authenticate with
    434    KyCH. This is passed in the ``client_id`` parameter during OAuth 2.0 flows
    435    and in the ``/setup/{client_id}`` endpoint URL.
    436 
    437 -  ``CLIENT_SECRET``: Shared secret for client authentication. The client
    438    provides this as a Bearer token in the ``Authorization`` header when calling
    439    ``/setup``, and in the request body when calling ``/token``. Use the
    440    ``secret-token:`` prefix per RFC 8959 for secrets that should not be logged.
    441    KyCH stores the secret as a bcrypt hash in the database.
    442 
    443 -  ``VERIFIER_URL``: Base URL of the Swiyu Verifier instance that this client
    444    will use for credential verification. Different clients can use different
    445    verifier instances (e.g., production vs. staging).
    446 
    447 -  ``VERIFIER_MANAGEMENT_API_PATH``: Path to the verifier's management API
    448    endpoint for creating verification requests. Default:
    449    ``/management/api/verifications``. Only change this if your Swiyu Verifier
    450    uses a non-standard API path.
    451 
    452 -  ``REDIRECT_URI``: The OAuth 2.0 redirect URI where users are sent after
    453    completing verification. This must exactly match the ``redirect_uri``
    454    parameter provided by the client in authorization requests. For security,
    455    KyCH rejects requests with mismatched redirect URIs.
    456 
    457 -  ``ACCEPTED_ISSUER_DIDS``: List of trusted credential issuer DIDs (Decentralized
    458    Identifiers) in bracketed format. Only credentials issued by these DIDs will
    459    be accepted. This provides trust anchoring - you specify which issuers you
    460    trust to have properly verified identities. Example:
    461    ``{did:tdw:issuer1, did:tdw:issuer2}``.
    462 
    463 
    464 CLI-based client management
    465 ---------------------------
    466 
    467 The ``kych-client-management`` tool manages clients directly in the database.
    468 All commands require the ``--config`` option to specify the configuration file
    469 (for database connection settings).
    470 
    471 **Listing clients:**
    472 
    473 Display all registered clients:
    474 
    475 .. code-block:: shell-session
    476 
    477    $ kych-client-management --config /etc/kych/kych.conf list
    478 
    479 This shows a summary of all clients including their IDs and verifier URLs.
    480 
    481 **Viewing client details:**
    482 
    483 Show full details for a specific client:
    484 
    485 .. code-block:: shell-session
    486 
    487    $ kych-client-management --config /etc/kych/kych.conf show exchange_prod
    488 
    489 This displays all configuration options for the client, except the secret
    490 (which is stored as a hash).
    491 
    492 **Creating a client:**
    493 
    494 Register a new OAuth 2.0 client:
    495 
    496 .. code-block:: shell-session
    497 
    498    $ kych-client-management --config /etc/kych/kych.conf create \
    499        --client-id exchange_prod \
    500        --secret "secret-token:your-secure-secret" \
    501        --verifier-url https://swiyu-verifier.example.com \
    502        --redirect-uri https://exchange.example.com/kyc/kych-redirect \
    503        --accepted-issuer-dids "{did:tdw:trusted_issuer}"
    504 
    505 The ``--client-id``, ``--secret``, ``--verifier-url``, and ``--redirect-uri``
    506 options are required. The ``--verifier-api-path`` defaults to
    507 ``/management/api/verifications`` if not specified.
    508 
    509 **Updating a client:**
    510 
    511 Modify an existing client's configuration:
    512 
    513 .. code-block:: shell-session
    514 
    515    $ kych-client-management --config /etc/kych/kych.conf update exchange_prod \
    516        --redirect-uri https://new-exchange.example.com/kyc/kych-redirect
    517 
    518 Only the specified options are updated; other settings remain unchanged.
    519 
    520 **Deleting a client:**
    521 
    522 Remove a client from the database:
    523 
    524 .. code-block:: shell-session
    525 
    526    $ kych-client-management --config /etc/kych/kych.conf delete exchange_prod
    527 
    528 You will be prompted for confirmation. Use ``-y`` to skip the prompt:
    529 
    530 .. code-block:: shell-session
    531 
    532    $ kych-client-management --config /etc/kych/kych.conf delete exchange_prod -y
    533 
    534 .. warning::
    535 
    536    Deleting a client will cascade to all associated sessions and tokens.
    537 
    538 **Synchronizing configuration to database:**
    539 
    540 The ``sync`` command is the bridge between configuration-based and database-based
    541 client management. It reads all ``[client_*]`` sections from the configuration
    542 file and creates or updates the corresponding clients in the database:
    543 
    544 .. code-block:: shell-session
    545 
    546    $ kych-client-management --config /etc/kych/kych.conf sync
    547 
    548 This is useful for infrastructure-as-code workflows where client configuration
    549 is managed in version control and deployed to the database during releases.
    550 
    551 To also remove clients from the database that are no longer defined in the
    552 configuration file, use the ``--prune`` flag:
    553 
    554 .. code-block:: shell-session
    555 
    556    $ kych-client-management --config /etc/kych/kych.conf sync --prune
    557 
    558 .. warning::
    559 
    560    The ``--prune`` flag will delete clients and all their associated sessions
    561    and tokens. Use with caution in production.
    562 
    563 
    564 Deployment
    565 ==========
    566 
    567 systemd service
    568 ---------------
    569 
    570 Create a systemd service file for KyCH:
    571 
    572 .. code-block:: ini
    573    :caption: /etc/systemd/system/kych.service
    574 
    575    [Unit]
    576    Description=KyCH OAuth2 Gateway
    577    After=network.target postgresql.service
    578 
    579    [Service]
    580    Type=simple
    581    User=kych
    582    Group=kych
    583    ExecStart=/usr/local/bin/kych-oauth2-gateway --config /etc/kych/kych.conf
    584    Restart=always
    585    RestartSec=5
    586 
    587    [Install]
    588    WantedBy=multi-user.target
    589 
    590 Enable and start the service:
    591 
    592 .. code-block:: shell-session
    593 
    594    [root@server]# systemctl daemon-reload
    595    [root@server]# systemctl enable kych
    596    [root@server]# systemctl start kych
    597 
    598 
    599 Reverse proxy setup
    600 -------------------
    601 
    602 KyCH should be deployed behind a reverse proxy that provides TLS termination,
    603 as required by OAuth 2.0. The following example shows an nginx configuration
    604 using a Unix socket:
    605 
    606 .. code-block:: nginx
    607    :caption: /etc/nginx/sites-available/kych
    608 
    609    upstream kych {
    610        server unix:/run/kych/kych.sock;
    611    }
    612 
    613    server {
    614        listen 443 ssl http2;
    615        server_name kych.example.com;
    616 
    617        ssl_certificate /etc/letsencrypt/live/kych.example.com/fullchain.pem;
    618        ssl_certificate_key /etc/letsencrypt/live/kych.example.com/privkey.pem;
    619 
    620        location / {
    621            proxy_pass http://kych;
    622            proxy_set_header Host $host;
    623            proxy_set_header X-Real-IP $remote_addr;
    624            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    625            proxy_set_header X-Forwarded-Proto $scheme;
    626        }
    627    }
    628 
    629 Enable the site:
    630 
    631 .. code-block:: shell-session
    632 
    633    [root@server]# ln -s /etc/nginx/sites-available/kych /etc/nginx/sites-enabled/kych
    634    [root@server]# nginx -t
    635    [root@server]# systemctl reload nginx
    636 
    637 
    638 Webhook configuration
    639 ---------------------
    640 
    641 KyCH receives callbacks from the Swiyu Verifier when a verification request
    642 changes state (e.g., when the user presents their credential). The webhook
    643 endpoint is ``/notification``.
    644 
    645 When configuring the Swiyu Verifier, set the callback URL to:
    646 
    647 ::
    648 
    649    https://kych.example.com/notification
    650 
    651 This endpoint must be accessible from the Swiyu Verifier service.
    652 
    653 .. note::
    654 
    655    The Swiyu Verifier must be configured to send notifications to the KyCH
    656    gateway. Consult the Swiyu Verifier documentation for details on configuring
    657    webhook callbacks. The verifier will POST a JSON payload containing the
    658    ``verification_id`` and ``timestamp`` when a verification completes.
    659 
    660 
    661 Integration with Taler Exchange
    662 ===============================
    663 
    664 To use KyCH as a KYC provider for a GNU Taler exchange, configure the
    665 exchange with the following settings:
    666 
    667 .. code-block:: ini
    668    :caption: /etc/taler-exchange/conf.d/exchange-kyc.conf
    669 
    670    [kyc-provider-kych]
    671    LOGIC = oauth2
    672    PROVIDED_CHECKS = KYCH_IDENTITY
    673    KYC_OAUTH2_AUTHORIZE_URL = https://kych.example.com/authorize
    674    KYC_OAUTH2_TOKEN_URL = https://kych.example.com/token
    675    KYC_OAUTH2_INFO_URL = https://kych.example.com/info
    676    KYC_OAUTH2_CLIENT_ID = exchange_production
    677    KYC_OAUTH2_CLIENT_SECRET = secret-token:your-secure-secret
    678    KYC_OAUTH2_POST_URL = https://kych.example.com
    679 
    680 The exchange will then use KyCH for KYC verification when the
    681 ``KYCH_IDENTITY`` check is required.
    682 
    683 
    684 OAuth 2.0 endpoints
    685 -------------------
    686 
    687 KyCH provides the following OAuth 2.0 endpoints:
    688 
    689 -  ``/authorize`` - Authorization endpoint (redirects user to Swiyu Wallet flow)
    690 -  ``/token`` - Token endpoint (exchanges authorization code for access token)
    691 -  ``/info`` - Info endpoint (returns verified identity claims)
    692 
    693 The flow follows standard OAuth 2.0 authorization code grant:
    694 
    695 1. Client redirects user to ``/authorize`` with ``client_id``, ``redirect_uri``,
    696    ``response_type=code``, and optional ``state`` parameter.
    697 
    698 2. User completes verification via Swiyu Wallet.
    699 
    700 3. User is redirected to the client's ``redirect_uri`` with an authorization
    701    ``code``.
    702 
    703 4. Client exchanges the ``code`` for an ``access_token`` at ``/token``.
    704 
    705 5. Client retrieves user information using the ``access_token`` at ``/info``.