# jira oauth error invalid_code grant type

## TL;DR
An invalid_code almost always means the authorization code was already used or has expired. Log your token exchanges and confirm the code is exchanged exactly once, within its short lifetime, with a redirect URI byte-identical to the one registered. Then start a fresh authorize flow and exchange the new code promptly.

```text
jira oauth error invalid_code grant type
```

## Use this when

- Jira OAuth fails at the token step with invalid_code
- The error appears intermittently, especially under retries
- The integration worked in testing but fails in production traffic

## Not for this skill when

- invalid_client or invalid_secret errors (credential problem instead)
- Refresh token failures on long-lived integrations (different flow)
- User-facing consent screen errors (happens before any code exists)

## Steps

### Step 1: Confirm single exchange

Add logging around the token endpoint call and check whether the same authorization code is being exchanged more than once (retry middleware plus manual retry is the classic double). Expected: each code appears in exactly one token request.

### Step 2: Verify the redirect URI matches exactly

Compare the redirect_uri sent in the authorize request, the token request, and the registered app settings, character by character including trailing slashes. Expected: all three are identical.

### Step 3: Check the code lifetime

Confirm how long the code sat between issuance and exchange; most providers allow minutes, some only one. Expected: the exchange happens within seconds of the callback.

### Step 4: Start a fresh authorize flow

Send the user through the authorize URL again to mint a brand-new code. Expected: a new code arrives at your callback.

### Step 5: Exchange once, immediately

Exchange the fresh code a single time right away and store the resulting tokens. Expected: the token endpoint returns an access token instead of invalid_code.

### Step 6: Harden the exchange path

Make the token exchange non-retryable on invalid_code and alert on it, since retrying a burned code can never succeed. Expected: future double-exchange bugs surface as alerts, not silent failures.

## Tool compatibility

Jira Cloud OAuth 2.0 (3LO); OAuth 2.0 authorization code grant; any backend exchanging codes at the token endpoint.

## Variant phrasings

### Variant 1

jira oauth invalid_code authorization code expired

### Variant 2

jira 3lo oauth token exchange invalid_code fix

### Variant 3

oauth authorization code already used invalid_code jira

## Why it happens

OAuth authorization codes are single-use credentials with a deliberately short life: use it once, quickly, or lose it. The invalid_code error is the provider telling you the code is already spent or stale. In practice the cause is rarely the provider; it is the application's own plumbing. Retry logic that replays the token call, a frontend and backend that both try to exchange the same code, or a slow queue that holds the callback for minutes all burn the code before the real exchange happens. Because the error text does not say which of these happened, the fix starts with logging every exchange, which immediately reveals doubles and delays.

## Edge cases / pitfalls

- PKCE flows add a second way to fail: a mismatched code verifier also surfaces as an invalid grant, so check the verifier too.
- Clock skew on the token call does not cause invalid_code, but it does cause neighboring errors; fix the clock separately.
- Some providers invalidate all outstanding codes when a new authorize starts; avoid parallel authorize attempts for one user.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_YQbninsxhcQg5l_3r7A2aw
