-
Notifications
You must be signed in to change notification settings - Fork 161
Description
Describe the bug?
The createClientAssertion function in okta/client.go sets the JWT exp claim to exactly 1 hour (time.Hour * time.Duration(1)):
https://github.com/okta/okta-sdk-golang/blob/master/okta/client.go#L765
Expiry: jwt.NewNumericDate(time.Now().Add(time.Hour * time.Duration(1))),Okta's documentation states the client_assertion JWT must have an expiration of "maximum of only one hour". However, Okta enforces this as strictly less than 3600 seconds, not less than or equal.
When the client machine's clock is even slightly ahead of Okta's servers (common with NTP sync variance), the JWT expiration appears to Okta as >3600 seconds and is rejected with:
"The client_assertion token has an expiration too far into the future"
This results in OAuth2 authentication failing with "Empty access token" when using private_key authentication.
What is expected to happen?
OAuth2 authentication using private_key should succeed regardless of minor clock skew (within reasonable bounds like ±5 seconds) between the client and Okta servers.
The JWT expiration should have a safety margin (e.g., 55 minutes instead of exactly 60) to account for normal clock drift.
What is the actual behavior?
When the client's clock is ahead of Okta's servers by even 1-2 seconds, the OAuth2 token request fails with:
{
"error": "invalid_client",
"error_description": "The client_assertion token has an expiration too far into the future. Please see https://developer.okta.com/docs/reference/api/oidc/#token-claims-for-client-authentication-with-client-secret-or-private-key-jwt for the requirements."
}
### Reproduction Steps?
1. Configure Okta SDK with OAuth2 private_key authentication
2. Ensure your machine's clock is synced or slightly ahead of Okta's servers
3. Attempt any API call that triggers authentication
To verify clock skew against Okta:
```bash
echo "Okta: $(curl -sI https://YOUR_ORG.okta.com | grep -i '^date:' | cut -d' ' -f2-)"
echo "Local: $(date -u '+%a, %d %b %Y %H:%M:%S GMT')"To confirm the boundary issue with a Python test:
import time, jwt, requests
OKTA_DOMAIN = "https://YOUR_ORG.okta.com"
CLIENT_ID = "your_client_id"
PRIVATE_KEY_ID = "your_key_id"
PRIVATE_KEY = open('private_key.pem').read()
def test(exp_seconds):
now = int(time.time())
claims = {
'iss': CLIENT_ID, 'sub': CLIENT_ID,
'aud': f"{OKTA_DOMAIN}/oauth2/v1/token",
'iat': now, 'exp': now + exp_seconds
}
assertion = jwt.encode(claims, PRIVATE_KEY, algorithm='RS256',
headers={'kid': PRIVATE_KEY_ID})
data = {
'grant_type': 'client_credentials',
'scope': 'okta.users.read',
'client_assertion_type': 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
'client_assertion': assertion
}
return requests.post(f"{OKTA_DOMAIN}/oauth2/v1/token", data=data).status_code
# Test boundary
for minutes in [57, 58, 59, 60, 61]:
status = test(minutes * 60)
print(f"{minutes} min: {status}") # 59 min = 200, 60 min = 401Additional Information?
No response
Golang Version
Not directly relevant - issue is in SDK logic, not Go version specific
SDK Version
v6.0.3 (also v5.0.6 and v4.1.2 - terraform-provider-okta v6.5.5 uses multiple SDK versions)
OS version
No response