Skip to main content

Refresh Token logic intermittently fails


Forum|alt.badge.img+1

Refresh Token logic intermittently fails

We're experiencing intermittent issues with the OAuth refresh token flow. While our initial token fetch consistently works (200 response from `/oauth2/v1/token`), some users encounter a 400 error during token refresh with:

{
"error": "invalid_grant",
"error_description": "Invalid token."
}

The peculiar aspect is that this only affects some users while working perfectly for others. The initial token exchange works flawlessly in all cases.

I've compared our implementation with the official Airtable example repo and can't seem to find any breaking differences.

Has anyone encountered similar issues or can suggest specific areas to investigate? We're particularly interested in understanding what could cause this intermittent behavior.

Technical details of our implementation are available if needed.

def refresh_airtable_token(token_type, refresh_token): """ Refresh the Airtable API token. """ token_url = "https://airtable.com/oauth2/v1/token" client_id = OAUTH_CREDENTIALS["airtable_client_id"] client_secret = OAUTH_CREDENTIALS["airtable_client_secret"] # Concatenate client_id and client_secret with a colon credentials = f'{client_id}:{client_secret}' # Encode the credentials in base64 format encoded_credentials = base64.b64encode(credentials.encode()).decode() headers = { 'Authorization': f'Basic {encoded_credentials}', 'Content-Type': 'application/x-www-form-urlencoded' } body = { 'grant_type': 'refresh_token', 'refresh_token': refresh_token, 'scope': 'data.records:read data.records:write data.recordComments:read data.recordComments:write schema.bases:read schema.bases:write user.email:read webhook:manage', 'client_id': client_id } response = requests.post(token_url, headers=headers, data=body) token_data = response.json() token_data['expires_at'] = get_token_expiry_dt(token_data) if 'access_token' not in token_data: raise ValueError( f"Failed to refresh token. Error: {token_data.get('error_description')}") return token_data def get_token_expiry_dt(token_data): # 'expires_in' not required to be returned by the OAuth 2.0 protocol. If it's not returned, just make it refresh next time too expires_in = token_data.get('expires_in') or 0 # Calculate the expiration datetime -- 10% time buffer instituted for expire time# current_time = get_datetime_ts() expires_at = current_time + timedelta(seconds=expires_in * 0.9) # Modify the json_response to include 'expires_at' # Represent it in ISO8601 UTC format return expires_at.isoformat()

 

Reply