fix(oauth): treat missing expires_in as non-expiring device_code token
GitHub OAuth Apps issue tokens that never expire and omit expires_in from the response (they only send access_token, token_type, scope). RFC 6749 §5.1 allows this — expires_in is only REQUIRED for tokens that actually expire. When expires_in is missing, save the token with expires_at = i64::MAX so prepare_oauth_access_token never tries to refresh. If the token is ever revoked server-side, the eventual 401 on the API call is the user's cue to re-authenticate. No effect on providers that include expires_in (Moonshot etc. — unchanged).
This commit is contained in:
+4
-4
@@ -479,10 +479,10 @@ async fn run_device_code_flow(provider: &dyn OAuthProvider, client_name: &str) -
|
|||||||
|
|
||||||
if let Some(access_token) = token_response["access_token"].as_str() {
|
if let Some(access_token) = token_response["access_token"].as_str() {
|
||||||
let refresh_token = token_response["refresh_token"].as_str().map(str::to_string);
|
let refresh_token = token_response["refresh_token"].as_str().map(str::to_string);
|
||||||
let expires_in_secs = token_response["expires_in"].as_i64().ok_or_else(|| {
|
let expires_at = match token_response["expires_in"].as_i64() {
|
||||||
anyhow!("Missing expires_in in device_code token response: {token_response}")
|
Some(secs) => Utc::now().timestamp() + secs,
|
||||||
})?;
|
None => i64::MAX,
|
||||||
let expires_at = Utc::now().timestamp() + expires_in_secs;
|
};
|
||||||
let account_id = provider.extract_account_id(&token_response);
|
let account_id = provider.extract_account_id(&token_response);
|
||||||
|
|
||||||
let tokens = OAuthTokens {
|
let tokens = OAuthTokens {
|
||||||
|
|||||||
Reference in New Issue
Block a user