Everything on this page is about local testing. In production, where Veriqa has a real
domain and a valid certificate, none of it applies: the production setup is simpler than the
local one.
The certificate
A self-signed certificate has to be mounted inside every container, followed byupdate-ca-certificates — otherwise PHP’s cURL breaks the code-for-tokens exchange. In production
this step does not exist at all.
A separate trap: antivirus software that intercepts TLS replaces your self-signed certificate
with its own and shows an “untrusted certificate” interstitial. The “continue” link on such a page
drops the query string — that is, the whole OIDC request — so you cannot get past it, either by
hand or programmatically. Server-side calls are unaffected: PHP inside the container uses the mounted
CA and never sees the problem.
A workaround that does not touch the machine’s security settings: expose two HTTPS endpoints —
one with your own certificate for the containers, and one with a dev certificate already trusted
by the system for your own browser.
The issuer address
Three rules:- the issuer must be https. On
http://localhost:5200the core refuses even in Development. Note that aredirect_urioverhttpis still accepted — the restriction is about the issuer address specifically; - the address must resolve identically from inside the container and from the host, or the
issin discovery drifts away from what the browser sees; - a private address is blocked by clients.
host.docker.internalis a private network, and almost every system guards against calls there with a flag of its own: WordPress cuts such requests off viawp_safe_remote_post()(fixed by theallow_internal_idpsetting), Drupal viaallow_private_issuer, Nextcloud viaallow_local_remote_servers, Discourse viaallowed_internal_hosts, Moodle viacurlsecurityblockedhosts. In production the address is public and none of these flags are needed.
Hop mode on a local setup
Hop mode is worth trying locally — it is the setting we recommend for production. It adds one condition to the issuer rules above: the QR code carries a link to the issuer address, and the phone opens it. A phone cannot reachlocalhost on your
machine, and it does not trust your self-signed certificate.
Put Veriqa behind an HTTPS tunnel — any service that gives a local port a public https
address with a valid certificate — and set that address as the issuer
(Veriqa:OpenIddict:Server:Issuer). The rule about one address everywhere applies here too: the
browser, the containers and the phone must all see the tunnel address, not localhost. Then switch
hop mode on with Veriqa:HopMode:Enabled = true.
In production none of this is needed: the issuer is already a public https address.
Environment odds and ends
429. Leave a pause between attempts.
What a local setup does not verify
- mail deliverability — SPF, DKIM, DMARC and domain reputation mean nothing to a local catcher;
- vendor platform behavior — Shopify and Wix reach Veriqa from the outside and need its public HTTPS address, see SaaS builders;
- performance under load — local response numbers say nothing about production.