PingFederate study materials
PingFederate study resources

Public SPA Refresh Failures After PKCE and Rotation

PingFederate · Put your knowledge to work in context.

All case studies

Public SPA Refresh Failures After PKCE and Rotation

PingFederate 12.0 is your OAuth 2.0 authorization server and OIDC provider. You have three clients: a browser-based single-page application (public client), a server-side web application (confidential client), and a backend service (client credentials). Access tokens last 15 minutes, refresh tokens last 8 hours, and persistent grants are set to 30 days. After you enabled mandatory PKCE for authorization-code clients and refresh-token rotation, the SPA began receiving invalid_grant errors when it tries to refresh after roughly 30 minutes. The web application and service are unaffected. The SPA keeps the refresh token only in memory, opens up to three tabs, and each tab has its own refresh timer. Its token endpoint authentication method is currently client_secret_basic, and the secret is embedded in JavaScript. The product owner wants users to stay signed in for 30 days without exposing a secret.

1. Diagnose the likely cause of the SPA invalid_grant errors and explain what evidence you would check in PingFederate before changing configuration.

Read the worked answer

invalid_grant at refresh normally means the refresh token presented is not the current grant: it was rotated out, expired, revoked, or is bound to a different client. With three tabs each refreshing independently, the first refresh rotates the token and the other tabs present the now-stale token. A retry with the old value produces the same error again. The embedded secret and client_secret_basic are also wrong for a public SPA: a browser cannot keep a secret, and PingFederate may be treating the client as confidential or rejecting the authentication method. Check the OAuth audit and server logs for the client ID, grant ID, token endpoint status, and whether the grant was rotated or revoked. Confirm persistent grants are enabled and that the refresh token lifetime has not expired. Check system clocks. Do not disable rotation globally to hide a client race; fix the client behavior first.

2. Recommend the corrected client configuration and token lifetimes for the SPA, web app, and service. Justify each choice against the 30-day sign-in requirement.

Read the worked answer

For the SPA, register it as a public client with token endpoint authentication method none, authorization code grant, and PKCE with S256. Remove the embedded secret. Keep refresh-token rotation on, serialize refresh across tabs with a single-flight lock or BroadcastChannel, and store the refresh token in the most secure browser storage the risk profile allows. Do not use client credentials in a browser.

For the web app, keep authorization code with a confidential client secret and rotate the secret on a schedule. For the backend service, keep client credentials and no refresh token.

Access tokens at 15 minutes are reasonable. Refresh tokens at 8 hours cannot meet a 30-day sign-in requirement, so raise refresh-token lifetime and persistent-grant maximum to at least 30 days only after accepting the risk that a stolen refresh token remains usable until expiry or revocation. Persistent grants must be enabled so refresh tokens survive PingFederate restarts. Test with an idle grant, a multi-tab refresh, and an explicit revocation.