Skip to main content
Here the backend, not the browser, starts the transaction: it asks a person to confirm an action in a messenger and acts on the outcome. There is no sign-in and no browser redirect. The three samples live under samples/dotnet/inproc/ in the repository (veriqa.app/source) and are MIT-licensed.

How each of them works

Every sample is one process in two roles: the Veriqa issuer (embedded) and the backend that calls it only over the public HTTP API. Point the backend at a standalone Veriqa and it works the same.
  1. POST /connect/token with grant_type=client_credentials.
  2. POST /api/transaction/confirmation with the declared action_type and its slot_values.
  3. The page shows channel_entry.qr — the QR image the API returns — for the user to scan with their phone.
  4. The backend polls GET /api/transaction/{id}/result.
  5. On confirmed it may exchange the transaction once for the id_token of the person who confirmed (grant_type=urn:veriqa:params:oauth:grant-type:confirmation).
The full contract — fields, errors, the exchange — is in the confirmation API reference.

The configuration that makes it work

The backend’s client entry in appsettings.json carries:
  • AllowClientCredentials: true — the backend may get a token for the API (needs a ClientSecret);
  • AllowConfirmationTokenGrant: true and openid in AllowedScopes — step 5;
  • MessageTemplates:<action type> — the declaration of the action: Contract:Slots and Templates. It belongs in the client entry; an action type declared only at the host level is refused with action_type_unknown;
  • for step-up also IdentityMatchComparableTypes, which declares the identity compared with the person who confirmed. Without it the request is refused with candidate_type_undeclared.
The host section sets Veriqa:Channels:OutcomeNotice:DisplayIntent to NewMessage: the receipt arrives as a message of its own and the question with the wording of the action stays in the conversation. See OutcomeNotice in Configuration.

Run a sample

Each sample needs a trusted local HTTPS certificate (dotnet dev-certs https --trust) and a Telegram bot token from @BotFather. Pass the token through user secrets, not a committed file:
For step-up and agent-approval replace the project path. In Development the bot runs in polling mode, so no public URL is needed. Without an enabled channel, creating a confirmation fails with 503 channel_display_failed. What to try in each:
  • confirmation — click Ask for approval, confirm in the bot: the page shows Outcome: confirmed and the claims of the id_token.
  • step-up — delete a project: the first person to confirm becomes the owner. Delete another one from a different Telegram account: the confirmation succeeds, but the page shows Not deleted — confirmed, but not by the owner.
  • agent-approval — click Hand the ticket to the agent: the agent stops at refund_payment until you approve. Decline on a second run: the refund is not executed and the agent tells the customer a colleague will contact them. The agent follows a fixed plan, so no model or API key is needed.

See also