spring-projects/spring-security · error
Invalidated device code used by registered client '%s'
Error message
Invalidated device code used by registered client '%s'
What it means
Emitted by OAuth2DeviceCodeAuthenticationProvider when a client attempts to redeem a device code that was issued to a different client. The provider invalidates the device code to prevent further use, saves the authorization, logs this warning, and throws OAuth2AuthenticationException with INVALID_GRANT. This is a cross-client replay defense for the device authorization grant (RFC 8628).
Source
Thrown at oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2DeviceCodeAuthenticationProvider.java:133
if (authorization == null) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_GRANT);
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Retrieved authorization with device code");
}
OAuth2Authorization.Token<OAuth2DeviceCode> deviceCode = authorization.getToken(OAuth2DeviceCode.class);
Assert.notNull(deviceCode, "deviceCode cannot be null");
if (!registeredClient.getId().equals(authorization.getRegisteredClientId())) {
if (!deviceCode.isInvalidated()) {
// Invalidate the device code given that a different client is attempting
// to use it
authorization = OAuth2Authorization.from(authorization).invalidate(deviceCode.getToken()).build();
this.authorizationService.save(authorization);
if (this.logger.isWarnEnabled()) {
this.logger.warn(LogMessage.format("Invalidated device code used by registered client '%s'",
authorization.getRegisteredClientId()));
}
}
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_GRANT);
}
// In https://www.rfc-editor.org/rfc/rfc8628.html#section-3.5,
// the following error codes are defined:
// expired_token
// The "device_code" has expired, and the device authorization
// session has concluded. The client MAY commence a new device
// authorization request but SHOULD wait for user interaction before
// restarting to avoid unnecessary polling.
if (deviceCode.isExpired()) {
if (!deviceCode.isInvalidated()) {
// Invalidate the device code
authorization = OAuth2Authorization.from(authorization).invalidate(deviceCode.getToken()).build();View on GitHub (pinned to 96852e8860)
Solutions
- Ensure the token request uses exactly the same client_id that started the device authorization flow.
- Check client configuration (application.yml / RegisteredClient settings) so the correct client_id is sent in the device token request.
- Do not share device codes between applications; run the device flow again for the second client.
- If tokens are unexpectedly revoked, restart the device authorization flow for the correct client.
Example fix
// before String clientId = "wrong-app"; // hardcoded from another service client.deviceAccessToken(code, clientId); // after String clientId = config.getOwnClientId(); client.deviceAccessToken(code, clientId);
Defensive patterns
Strategy: validation
Validate before calling
// verify client identity before redeeming a device code
if (!issuedClientId.equals(this.clientId)) {
throw new IllegalStateException("device code was issued to a different client; start your own device flow");
} Try / catch
try {
TokenResponse r = redeemDeviceCode(deviceCode);
} catch (OAuth2AuthenticationException e) {
if ("invalid_grant".equals(e.getError().getErrorCode())) {
// code invalidated (cross-client use): restart the device authorization flow
startDeviceAuthorization();
}
} Prevention
- Never share device codes or verification URIs across client applications
- Keep client_id configuration consistent between authorization and token requests
- Give each environment (dev/stage/prod) its own registered clients
- On invalid_grant, restart the device flow rather than retrying the same code
When it happens
Trigger: During the device access token request, the client_id of the caller does not match the registered client that originally received the device code (e.g. a different device code flow instance, a misconfigured client_id, or a code copied to another application).
Common situations: Copy-pasting a verification URL/device code between two apps configured against the same authorization server, an environment mismatch where staging and prod clients share a database, or a typo/wrong client_id in the token request.
Related errors
- Invalidated user code used by registered client '%s'
- server_error
- OAuth 2.0 Parameter: + parameterName
- Invalidated authorization code used by registered client '%s
- Invalidated authorization token(s) previously issued to regi
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/2ec2b01cc656d26e.
Report an issue: GitHub.