theonedev/onedev · error · ExplicitException
OAuth token refresh error: ${getErrorMessage(errorResponse.g
Error message
OAuth token refresh error: ${getErrorMessage(errorResponse.getErrorObject())} What it means
DefaultOAuthTokenService.requestTokens performs the OAuth token exchange/refresh against the authorization server. When the token endpoint returns a non-success response, the error object is converted to a message via getErrorMessage and thrown as ExplicitException (surfaced as 'OAuth token refresh error: ...'). This indicates the OAuth provider rejected the token request or refresh — e.g. invalid grant, bad client credentials, or expired refresh token.
Source
Thrown at server-core/src/main/java/io/onedev/server/util/oauth/DefaultOAuthTokenService.java:76
new com.nimbusds.oauth2.sdk.token.RefreshToken(refreshTokenValue);
AuthorizationGrant refreshTokenGrant = new RefreshTokenGrant(refreshToken);
ClientAuthentication clientAuth = new ClientSecretBasic(
new ClientID(clientId), new Secret(clientSecret));
TokenResponse response;
try {
TokenRequest request = new TokenRequest(new URI(tokenEndpoint), clientAuth, refreshTokenGrant, null);
response = TokenResponse.parse(request.toHTTPRequest().send());
} catch (ParseException | URISyntaxException | IOException e) {
throw new RuntimeException(e);
}
if (response.indicatesSuccess()) {
return response.toSuccessResponse().getTokens();
} else {
TokenErrorResponse errorResponse = response.toErrorResponse();
throw new ExplicitException(getErrorMessage(errorResponse.getErrorObject()));
}
}
@Listen
public void on(SystemStarted event) {
taskId = taskScheduler.schedule(this);
}
@Listen
public void on(SystemStopping event) {
if (taskId != null)
taskScheduler.unschedule(taskId);
}
@Override
public void execute() {
accessTokenCache.entrySet().removeIf(it -> it.getValue().isExpired());View on GitHub (pinned to d44925c47c)
Solutions
- Re-authorize the OAuth connection to obtain a fresh access/refresh token (re-run the login/link flow).
- Read the provider error in the message (e.g. invalid_grant, invalid_client) and fix accordingly — usually re-consent or credential update.
- Verify the OAuth app's client_id/client_secret and redirect URI configured on the server match the provider's settings.
- Check provider status/docs for changed token policies and update server config, then retry.
Example fix
// before: refresh token revoked -> invalid_grant on every refresh // after: re-authorize the account so a new refresh token is stored // Server admin: OAuth connection settings -> 'Authorize' again with the provider.
Defensive patterns
Strategy: try-catch
Validate before calling
// Before refreshing, check stored token presence and expiry:
boolean refreshPossible(OAuthToken token) {
return token != null && token.getRefreshToken() != null;
} Try / catch
try {
tokens = oAuthTokenService.tokens(...);
} catch (ExplicitException e) {
if (e.getMessage().startsWith("OAuth token refresh error")) {
// trigger re-authorization flow for the connection
} else throw e;
} Prevention
- Re-authorize OAuth connections periodically or when refresh tokens expire.
- Keep client_id/client_secret/redirect URI in sync with the provider after rotation.
- Monitor provider error codes (invalid_grant) and alert to prompt re-consent.
When it happens
Trigger: Calling requestTokens (via the tokens path) where the TokenResponse from the OAuth provider indicates failure: expired/revoked refresh token, wrong client_id/client_secret, redirect_uri mismatch, or the provider returning error codes like invalid_grant or invalid_client.
Common situations: Long-lived OAuth connections where the refresh token expired or was revoked; rotating the OAuth app's client secret without updating OneDev's server configuration; provider-side policy changes (token lifetimes, IP restrictions); clock skew invalidating tokens.
Related errors
- Authentication required
- Unauthenticated
- Not authenticated
- Unable to import build spec (import project: {0}, import rev
- Invalid access token
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/72c18957bf3cc5b5.
Report an issue: GitHub.