Skip to main content

OAuth request hardening

Always generate and verify state to prevent CSRF attacks
Always generate and verify nonce when requesting id_token
Use PKCE (S256) for every public client (SPA, mobile, desktop)
Register exact redirect URIs — no wildcards, no trailing-slash variations
Treat access_token, access_token_jwt, and refresh_token as secrets
Prefer server-side token storage (HTTP-only cookies, encrypted session)
If browser storage is necessary, use sessionStorage over localStorage — never localStorage for refresh tokens
Rotate app sessions after a refresh or privilege change
refresh_token grants long-lived access. A leaked refresh token lets an attacker impersonate the user until it’s revoked. Store it server-side whenever possible.
When validating an id_token JWT received from Ave, check all of the following:
Signature valid against JWKS from the Ave OIDC discovery document ({issuer}/.well-known/jwks.json, where issuer is the issuer value from /.well-known/openid-configuration)
iss equals the issuer value from the Ave OIDC discovery document (e.g. https://aveid.net on the hosted service)
aud equals your clientId (or origin:https://yourapp.com for Quick Ave)
exp is in the future
iat is recent (within an acceptable clock skew)
nonce matches the value you sent at authorization time
Reject tokens with missing or unexpected values for any of the above
Keep your service clocks synchronized (NTP). JWT validation is time-sensitive — a clock that’s off by more than a few minutes will cause false rejections or accept expired tokens.
Request the minimum set of connector scopes your app actually needs
Pin to known requestedResource values — don’t accept arbitrary resource keys from user input
Handle access_denied on token exchange as a normal user action (grant was revoked), not a system error
Never cache delegated tokens past their expires_in time
Include an anti-replay nonce or a unique operation ID in every signed payload
Set short expiration times for signing requests (default 300 s, max 3600 s)
Verify signatures server-side before performing any irreversible action
Use canonical, deterministic payload strings to avoid signature-mismatch bugs
Never perform side effects (transfers, permission changes, deletions) based solely on a pending signing request. Wait for status: "signed" and verify the Ed25519 signature before proceeding.
Normalize base64 fragments before decoding — replace (space) with +
Remove key-bearing URL fragments from browser history immediately after parsing
Keep per-identity encrypted data partitions — never mix data across identities
Never log raw key material
Use the embed SDK for iframe flows; it only accepts postMessage from the Ave issuer
Monitor spikes in invalid_grant errors — may indicate token replay or reuse attacks
Monitor spikes in invalid_scope errors — may indicate misconfigured clients or probing
Track refresh token failure patterns to detect stolen tokens
Alert on unusual signing denial/approval anomalies
Rotate app credentials (clientSecret) periodically
Last modified on April 13, 2026