| 3149 | } |
| 3150 | |
| 3151 | func shouldRefreshOIDCToken(link database.UserLink) (bool, time.Time) { |
| 3152 | if link.OAuthRefreshToken == "" { |
| 3153 | // We cannot refresh even if we wanted to |
| 3154 | return false, link.OAuthExpiry |
| 3155 | } |
| 3156 | |
| 3157 | if link.OAuthExpiry.IsZero() { |
| 3158 | // 0 expire means the token never expires, so we shouldn't refresh |
| 3159 | return false, link.OAuthExpiry |
| 3160 | } |
| 3161 | |
| 3162 | // This handles an edge case where the token is about to expire. A workspace |
| 3163 | // build takes a non-trivial amount of time. If the token is to expire during the |
| 3164 | // build, then the build risks failure. To mitigate this, refresh the token |
| 3165 | // prematurely. |
| 3166 | // |
| 3167 | // If an OIDC provider issues short-lived tokens less than our defined period, |
| 3168 | // the token will always be refreshed on every workspace build. |
| 3169 | // |
| 3170 | // By setting the expiration backwards, we are effectively shortening the |
| 3171 | // time a token can be alive for by 10 minutes. |
| 3172 | // Note: This is how it is done in the oauth2 package's own token refreshing logic. |
| 3173 | expiresAt := link.OAuthExpiry.Add(-time.Minute * 10) |
| 3174 | |
| 3175 | // Return if the token is assumed to be expired. |
| 3176 | return expiresAt.Before(dbtime.Now()), expiresAt |
| 3177 | } |
| 3178 | |
| 3179 | // ObtainOIDCAccessToken returns a valid OpenID Connect access token |
| 3180 | // for the user if it's able to obtain one, otherwise it returns an empty string. |