Back to scan results
Check 17 of 24

OAuth 2.0 / OIDC Security

If you operate an identity provider, your discovery document at /.well-known/openid-configuration tells the world exactly how secure (or insecure) your OAuth setup is. We fetch it and check the signing algorithms, supported flows, and PKCE support.

What this check probes

We GET /.well-known/openid-configuration and parse the JSON. If it's not present, the check is skipped (most sites are not identity providers). When found, we look at:

  • id_token_signing_alg_values_supported — the list of JWT algorithms the IdP accepts. "none" is a critical fail (lets anyone forge tokens). "HS256" alone is suspicious (symmetric key shared with all clients). Modern best practice: RS256, ES256, or EdDSA only.
  • code_challenge_methods_supported — must include "S256" for PKCE support. Without PKCE, public clients (mobile apps, SPAs) are vulnerable to authorization-code interception.
  • token_endpoint_auth_methods_supported — should include "client_secret_post" or "client_secret_basic". Avoid "none" for confidential clients.
  • response_types_supported — implicit flow ("token", "id_token token") is deprecated by OAuth 2.1; should be removed in favor of authorization code + PKCE.
  • JWKS reachability — the jwks_uri should be HTTPS and respond with valid JSON.

Why this matters for PCI DSS

The classic "alg: none" attack: an attacker takes a legitimate JWT, changes the algorithm header to "none", removes the signature, and substitutes their own claims. A library that honors the header value impersonates any user. CVE-2018-1000531, CVE-2015-9235, and many more.

Without PKCE, a malicious app on the same device can register a custom URL scheme handler and intercept the authorization code from the callback URL, then exchange it for a token.

PCI DSS 4.0 Requirement 8.3 covers strong authentication. Requirement 8.6 covers application/system account management. Requirement 6.2.4 covers injection and access-control attacks.

How to fix it

Remove "none" and weak algorithms from your IdP configuration. The setting is provider-specific:

  • Keycloak — Realm Settings → Tokens → "Default Signature Algorithm" (set to RS256), then Clients → per-client → "ID Token Signature Algorithm".
  • Auth0 — Application Settings → Advanced Settings → OAuth → JsonWebToken Signature Algorithm.
  • Okta — Apps → your application → General → OpenID Connect ID Token → Algorithm.
  • IdentityServer4 / Duende — server-side, register only RS256 in SigningCredentials.
  • Custom JWT verification code — never honor the alg header; pin to your expected algorithm and key.

Require PKCE for all authorization-code clients (not just public ones — it's now best practice for confidential clients too):

  • Keycloak: Client → Settings → "Proof Key for Code Exchange Code Challenge Method" = S256.
  • Auth0: enable "Require PKCE" toggle on the application settings.
  • Authorization request from the client must include code_challenge + code_challenge_method=S256.

Disable implicit flow at the IdP unless you have a specific legacy client that needs it. Authorization code + PKCE replaces every legitimate use case.

Validate the discovery document with oauth.tools or OpenID Connect Conformance Tests.

Fixed it? Re-run the scan to confirm.

Run scan again