#1626

[Bug]: Google Workspace OIDC never requests a refresh_token, so sessions can't survive token expiry

Opensuperbusy-devopened 3mo ago

Bug Description

On a Google Workspace OIDC deployment, hoop never obtains a refresh_token from Google in the first place, because GetAuthCodeURL only requests access_type=offline when the literal scope offline_access is present in the configured scopes:

https://github.com/hoophq/hoop/blob/main/gateway/idp/oidc/oidc.go#L240-L246

offline_access as a scope is an Auth0/Okta/Azure AD convention — Google never adopted it. Google signals "also return a refresh_token" exclusively via the access_type=offline query parameter, independent of scopes. So for a Google issuer, setting IDP_CUSTOM_SCOPES=offline_access is a no-op, no refresh_token is ever returned, and TryRefreshExpiredToken (gateway/idp/core.go) has nothing to work with once the ~1h Google access token expires.

Related to #1540, but a separate bug: that issue is about the gRPC keep-alive poll never attempting a refresh even when a valid refresh_token exists. This issue is about Google specifically never obtaining a refresh_token to begin with — so even after #1540's fix lands, a Google Workspace deployment would still be broken, since there'd be nothing to refresh with.

The codebase already has the correct Google-specific handling for a different, unrelated OAuth flow:

https://github.com/hoophq/hoop/blob/main/gateway/api/connections/connection_federation_oauth.go#L157-L162

That code explicitly sets oauth2.AccessTypeOffline + forces prompt=consent for Google. This was just never applied to the main login flow.

Steps to Reproduce

  1. Deploy the gateway with AUTH_METHOD=oidc, IDP_ISSUER=https://accounts.google.com, and Google Workspace as the IdP.
  2. Log in via hoop login or the webapp.
  3. Wait for the Google access token to expire (~1h) and for the gateway's 5-minute user-token poll to notice.
  4. Any active hoop connect session is terminated with "access token is expired"; the webapp session also requires a fresh interactive login.

Expected Behavior

The session should be silently renewed using a refresh_token, the way it already works (or should work, per #1540) for IdPs that follow the offline_access scope convention.

Actual Behavior

No refresh_token is ever requested from Google, so every session expiry requires a full interactive browser re-login.

Version

1.107.2

Browser(s)

N/A — this is a gateway/OIDC-provider issue, not browser-specific.

Operating System

N/A — server-side (gateway) issue; observed on a Linux/Docker deployment.

Screenshots

No response

Additional Context

Happy to submit a PR: detect the Google issuer (the codebase already does this exact check elsewhere for gsuite-groups sync, via the googleIssuerURL const at gateway/idp/oidc/oidc.go#L26,L111) and unconditionally request access_type=offline (+ prompt=consent on first login) for that issuer, instead of gating on the offline_access scope string.

Relevant Log Output

N/A

Code of Conduct

  • I agree to follow this project's Code of Conduct

Activity

1
github-actions[bot]3mo ago

🔗 Synced to Linear: SUP-164