otpless-headless-sdk v2.0.0. Pinning is disabled by default, so upgrading needs no code change.
Enable pinning
PasssslKind to initialise (the suspend overload — initialize does not take sslKind and always runs with pinning disabled):
OtplessSslKind values
Pin validation failure
If pin validation fails,OtplessSDK.start() returns a terminal response instead of continuing the auth flow:
responseType:FAILEDstatusCode:5004errorCode:"5004"errorMessage:"SSL pin validation failed"
5004 like any other terminal auth failure: show a fallback or retry path. Re-initialising resets the failed state and retries the manifest load.
What gets pinned
Pinned traffic goes to
sigma.otpless.app. Behind a firewall, proxy, or MDM allowlist, add sigma.otpless.app and d3efyv4lemhheo.cloudfront.net.How it works
- Baseline SPKI pins ship in the SDK and install immediately on
initialise(sslKind = OtplessSslKind.SslEnabled). - A signature-verified remote manifest can refine the pin set — it can add pins, but never remove a baseline pin or introduce a new host. A cached copy is reused for up to 7 days; otherwise a fresh one is fetched and verified.
- Pins are enforced at every TLS handshake, after system trust validation. Hosts outside the pin set pass through on system trust alone.
- On a pin mismatch the SDK refreshes the manifest once and re-checks. If it still fails, the connection is cancelled and pinning fails closed for the rest of the process.
- Certificate rotation needs no app update — new pins arrive via the signed manifest.
Debugging and testing
- Proxies are blocked by design. Charles, Proxyman, and mitmproxy present their own certificate, so
SslEnabledfails them with5004. UseSslDisabledin debug when you need to inspect traffic; keepSslEnabledin release. - Pinning is per connection, not per request — a reused TLS connection is checked once; a new connection is checked again.
Migration notes
- No code change to upgrade to v2.0.0; add
sslKind = OtplessSslKind.SslEnabledwhen you’re ready to enforce pinning. - Hosts reached through an
apiBaseUrloverride are not pinned — they pass through on system trust.