duplicate_grant error on repeated OAuth token request
0 reputation · 28 Oct 2020, 12:30 UTC
0 reputation · 28 Oct 2020, 12:30 UTC
Determine whether an authorization server treats a retried token request as idempotent by returning either a duplicate_grant error or the originally issued access token, thereby preventing duplicate writes after a transient failure.
The OAuth 2.0 RFC 6749 does not define idempotency for the token endpoint, so behavior varies: some servers detect duplicate grant parameters and return duplicate_grant, others may issue a new token, and the optional Idempotency‑Key header remains unimplemented in most deployments. Given this uncertainty, what response should a client expect, and how can it safely handle retries?
Does the server return duplicate_grant error for an identical token request after a timeout? If duplicate_grant is not returned, does it reuse the previously issued token instead of creating a new one? What client‑side mechanism guarantees idempotent token acquisition without relying on server‑specific behavior?
35270 reputation · 28 Oct 2020, 18:15 UTC
You should expect neither a duplicate_grant error nor reuse of the previously issued token as guaranteed behavior. RFC 6749 defines no idempotency requirement for the token endpoint, and duplicate_grant is not a registered error code — it exists only as a vendor-specific extension in some products. Whether a server returns it, mints a fresh token, or rejects the retry depends entirely on the implementation and the grant type. The only mechanism that guarantees idempotent token acquisition without relying on server behavior is a client-side token cache keyed by grant parameters plus single-flight locking.
The likely explanation for a duplicate_grant response, where it exists, is that the server keeps a short-lived record of processed grant parameters and matches identical retries against it. This is per-implementation, usually time-boxed, and absent from most deployments — do not code against it.
invalid_grant, and the spec says the server SHOULD revoke tokens already issued on that code. A blind retry can destroy the token your first request actually obtained.The Idempotency-Key header is not part of RFC 6749; most servers ignore unknown headers, so it provides no guarantee.
// Pseudocode: single-flight cached token acquisition
async function getToken(key, fetchFn) {
const cached = cache.get(key);
if (cached && cached.expiresAt > Date.now() + 60_000) return cached.token;
return locks.acquire(key, async () => { // concurrent callers wait here
const again = cache.get(key); // re-check inside the lock
if (again && again.expiresAt > Date.now() + 60_000) return again.token;
const tok = await fetchFn(); // one HTTP request per key
cache.set(key, tok);
return tok.token;
});
}For client_credentials, a single retry through the cache/lock path is safe. For authorization_code, do not retry the same code: persist redemption state before sending the request, and on invalid_grant restart the authorization flow instead of reusing the consumed code.
Because behavior is vendor- and version-specific, confirm it directly:
# Send the identical request twice and compare status, error, and token values
curl -s -X POST https://auth.example.com/token \
-d 'grant_type=client_credentials&client_id=ID&client_secret=SECRET&scope=read'To simulate the real failure, route the request through a proxy that drops the response after the server processes it, then retry and observe. Also check your server's documentation or logs for its code-reuse and revocation behavior.
One detail changes this recommendation: which grant type you are retrying, and which server product. Code-based grants need restart-on-invalid_grant handling; client_credentials needs only caching and single-flight.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.