Skip to main content

Veriqa, BCP 247 and the threat model

Checked against the RFC and the code: 2026-11-05

RFC 10027 is IETF Best Current Practice 247 on the security of cross-device flows, published in August 2026. It describes the threat model Veriqa works in: a sign-in starts in a browser on one device and is confirmed on a phone in a messaging app. The RFC requires you to assess the risks before you deploy a cross-device flow and to choose mitigations based on that assessment (§2, items 1 and 4, MUST). The table below is input for that assessment: for each of the 17 practical mitigations in Section 6.1 it shows whether Veriqa has it and where to check.

This is a snapshot of the check against the text of the RFC and the Veriqa source code made on November 5, 2026. The source of the table, with a detailed breakdown of every uncovered mitigation, is the Veriqa, BCP 247 and the threat model page in the documentation; if the two ever differ, the documentation is right.

Summary

Of the 17 mitigations in §6.1, Veriqa covers 7, partly covers 2 and does not cover 6; another 2 are addressed to parties other than the authorization server.

The table below describes each mitigation and the risks it addresses, including how to provide the mitigations the Veriqa core does not have.

To see whether Veriqa covers a lot or a little, we set out to compare how fully other common sign-in methods cover these mitigations. But RFC 10027 came out in August 2026, and ratings of other methods against it barely exist yet, so we rated them ourselves against the same table. An SMS code covers 2 mitigations and partly covers 2; another 7 are set by the server that sends the code rather than by the method itself. Google's sign-in with a code on another device (RFC 8628), going by Google's documentation, covers 3 and partly covers 2; Google has not published an assessment of its own against BCP 247.

An independent review of Amazon Cognito found settings for 3 of the 17 mitigations and none for 5; it does not address the other 9.

The strongest setup: passkeys alongside Veriqa

The confirmation in the messaging app is not tied to the browser where the session opens, so a Veriqa sign-in on its own is not phishing-resistant. The Passkeys alongside Veriqa scenario closes that gap: the user signs in through the messaging app, creates a passkey from a button that arrives in the same chat, and your application requires the key before it opens the session.

  • Veriqa brings an account without a sign-up form, a backup channel from the first sign-in and the button that creates the key in the messaging app.
  • The passkey brings phishing resistance: it does not sign a request for another origin, and signing in with a key from another device requires Bluetooth near the sign-in browser (§6.2.3.3).

A passkey is a proximity method in §6.1.1 and the phishing-resistant sign-in §6.1.15 describes, and the RFC recommends FIDO2/WebAuthn wherever the devices support it (§6.2.3.5, SHOULD). The protection comes from the mandatory mode: as long as sign-in without the key remains available, an attacker will use it. What to keep in mind when the first key is created is covered in the breakdown in the documentation.

Threat model

In RFC terms, Veriqa is the Authorization Server. The browser where the sign-in starts is the Consumption Device, and the phone with the messaging app is the Authorization Device. The QR code or the link travels from one device to the other over an unauthenticated channel, and only the user can verify that channel: "The only mitigation against this unauthenticated channel is the user's judgment" (§1.1).

This is what Cross-Device Consent Phishing (CDCP) exploits. The attacker starts a sign-in to the application themselves and, under some pretext, passes their QR code to the victim or shows it on a fake page. The victim confirms the sign-in in their messaging app, and the session opens for the attacker. The attacker does not get the messaging account — they get signed in to the application. Veriqa's flows are cross-device authorization flows (§3.1), so the RFC's second family of threats, Cross-Device Session Phishing (CDSP, §3.2), does not apply to them.

Veriqa's flows match the patterns in §3.1 as follows (the mapping is derived from the RFC's definitions; the RFC itself does not mention Veriqa):

Veriqa flow RFC pattern
A QR code or a link into a messaging app, the one-tap email, a confirmation your server creates User-Transferred Session Data (§3.1.1) — the same class as RFC 8628
A link in an email sent to the address typed on the sign-in page Backchannel-Transferred Session (§3.1.2) — the CIBA class
A code from an email, entered on the sign-in page User-Transferred Authorization Data (§3.1.3)

The initiator context in the question, short lifetimes and one-time codes lower the risk, but they do not protect against a forwarded sign-in. Only a mandatory passkey protects against it. The place factor, when the surface is picked based on the session, only stops browsers outside the office, and only if your application grants access after the presence check. Sign-in from trusted networks likewise only stops browsers outside those networks.

§6.1 mitigations in Veriqa

Statuses: covered — a Veriqa mechanism does what the mitigation describes; partly — part of the mitigation is covered, or only one of the flows; not covered — Veriqa does not have it; outside the product — the mitigation is addressed to someone other than the authorization server. The table primarily assesses the sign-in; a confirmation your server creates is counted where it complements the sign-in. Mitigation names are as in the RFC.

§ Mitigation What Veriqa has Status Where to check
6.1.1 Establish Proximity None of the RFC's four methods — physical connectivity, wireless, shared network, geolocation. In hop mode Veriqa collects the context of the phone that scanned the QR code as a risk signal, but does not match it against the sign-in device. The place factor works today as a recipe: after signing in, the person scans a QR code on an office surface — a printer, a meeting-room screen, an IP phone — and confirms in the messaging app, and your service picks the surface by the network or workstation of the session. What to do: passkeys, the place factor; direction — binding levels not covered Hop mode
6.1.2 Short-Lived/Time-Bound QR or User Codes A sign-in transaction expires after 300 seconds by default, a confirmation your server creates after 60 to 1800 seconds; the one-time hop link has a lifetime of its own covered TransactionTtlSeconds, ttl_seconds, HopMode.TokenLifetime
6.1.3 One-Time or Limited-Use Codes A transaction can be confirmed only once, and a finished one cannot be replayed; the hop link and the link handle are single-use covered Hop mode, link handle
6.1.4 Unique Codes The transaction identifier is 256 random bits from a cryptographically secure generator. A transaction is bound to the channel account in which it is opened first — by its QR code or by its link — and any other account is refused; tokens for it are issued only once. This implements the MAY to decline a code presented again, using the transaction state instead of a list of used codes. When a hop link is opened again in another browser, Veriqa warns the user covered TransactionId.NewId, TransactionService.BindChannelSubjectAsync in the source code; HopMode.WarnOnRepeatScan, true by default — Hop mode
6.1.5 Content Filtering Filtering email and messages is the job of email providers and messaging apps outside the product —
6.1.6 Detect and Remediate The transaction audit trail, flagging of an unusual sign-in context, token revocation, and introspection for clients allowed to use it. There is no chain of "attack detected → tokens issued for this code revoked → resource servers notified"; flagging of an unusual context is off by default and has no sign-in history to compare with yet; there is no "this wasn't me" button and no CAEP. Direction — anomaly detection partly Audit, AnomalyDetection:Enabled, EnableRevocation, introspection
6.1.7 Trusted Devices The core has no registry of trusted devices allowed to start a sign-in: any browser can start one. Only a confidential client of your backend can create a confirmation. In the place-factor scenario, you choose and register the display device. Direction — browser mark not covered Get a token
6.1.8 Trusted Networks The core has no list of networks a sign-in may start from; KnownIPNetworks only sets which proxies are trusted. Today the deployment perimeter is what limits sign-ins. What to do and direction — trusted network not covered Infrastructure
6.1.9 Limited Scopes By configuration: the client's AllowedScopes. Every Veriqa flow is cross-device, so the client's scopes are the scopes of these flows. There is no narrowing by risk — by device or place; the RFC allows it but does not require it ("may be further refined") covered Clients
6.1.10 Short-Lived Tokens By configuration: access tokens expire after 3600 seconds, refresh tokens after 1,209,600 seconds (14 days), refresh-token rotation is on covered Server, rotation
6.1.11 Rate Limits Route limits (starting a sign-in — 60 a minute, creating a confirmation — 60 a minute per client, starting an Email sign-in — 5 a minute) and a limit per channel user — 5 a minute. Sign-in emails are also counted per recipient: 5 an hour per address, and per domain if switched on covered Veriqa:RateLimit, limits, emails per address
6.1.12 Sender-Constrained Tokens Tokens are not bound to a sender key: no DPoP and no mTLS. No direction on this page not covered OIDC support
6.1.13 User Education Educating users is up to your service; the RFC makes this a MAY outside the product —
6.1.14 User Experience The question in the messaging app names the application, the time of the request, and the initiator's browser, OS and region, and ends with the advice If it was not you, decline the request. Below it are the "Confirm ✅" and "Decline ❌" buttons, with a red cross marking the refusal. On the Veriqa page that asks Yes or No and on the provider-account sign-in page, the default answer is No: that button is filled with the primary color and has focus when the page opens, while Yes is outlined. On a touch screen the provider page accepts Yes only via a slider. In a confirmation your server creates, you write the question, and the advice to decline is there if you added it covered Initiator context, Veriqa:LoginConfirmation, ConfirmSlider, confirmation templates
6.1.15 Authenticate then Initiate For a confirmation your server creates: your backend starts it after the user has signed in, and expected_identities ensures that only the account owner can confirm it. A repeated sign-in before a risky operation is also started by a user who has signed in, and the step-up recipe checks sub and auth_time in the new id_token. The mitigation does not apply to the sign-in itself: whoever starts it has not signed in yet. The mitigation assumes a phishing-resistant sign-in first — a mandatory passkey gives one partly What you check
6.1.16 Request Initiation Verification There is no separate one-time-code step. A sign-in with a code from an email is the flow itself (§3.1.3), not an added check. Direction — binding levels not covered Link, code or both
6.1.17 Request Binding with Out-of-Band Data None. No direction on this page not covered —

What to do about the uncovered mitigations

For every uncovered mitigation the documentation says what you can do today and which direction the product is taking:

Rate limits, auditing and token rotation before launch are covered in production hardening.