apereo/cas · error · AuthenticationException

Request is assigned an invalid device identifier

Error message

Request is assigned an invalid device identifier

What it means

AuthenticationException thrown by DefaultQRAuthenticationTokenValidatorService.validate when the device id claim (QR_AUTHENTICATION_DEVICE_ID) in the QR token does not match the device id presented in the validation request. The token is bound to the device that originally requested the QR code.

Solutions

  1. Display a fresh QR code on the requesting device and scan it from that same device/session.
  2. Ensure the client persists and consistently sends the same device id between QR generation and validation.
  3. Verify no middleware/browser privacy settings regenerate the device identifier mid-flow.
  4. Check that QR generation and validation use the same device id source (cookie/local storage key) in custom frontends.
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the request carries the same device id as the token
String tokenDeviceId = claims.getClaim(QR_AUTHENTICATION_DEVICE_ID, String.class);
if (tokenDeviceId != null && !tokenDeviceId.equalsIgnoreCase(requestDeviceId)) {
    return error("device mismatch; regenerate QR code");
}

Try / catch

try { validatorService.validate(request); } catch (AuthenticationException e) { if (e.getMessage().contains("invalid device identifier")) { return regenerateQrEvent(); } throw e; }

Prevention

When it happens

Trigger: Strings.CI.equals(tokenDeviceId, request.getDeviceId()) is false during QR token validation — request.getDeviceId() differs from the device id embedded in the JWT at mint time.

Common situations: User scans the QR code with a different device/browser profile than the one that displayed it; device id regenerated after cookies/storage cleared; multiple devices sharing a session with stale QR codes; device id not passed through correctly by the client integration.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/e71a3477fa34cafa. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-qr-authentication/src/main/java/org/apereo/cas/qr/validation/DefaultQRAuthenticationTokenValidatorService.java:66

        val authentication = tgt.getAuthentication();
        LOGGER.trace("Authentication attempt linked to [{}] is [{}]", tgt.getId(), authentication);

        if (!authentication.getPrincipal().getId().equals(claims.getSubject())) {
            val message = String.format("Token %s does not belong to the assigned principal", claims.getSubject());
            throw new AuthenticationException(message);
        }

        if (!claims.getIssuer().equals(casProperties.getServer().getPrefix())) {
            val message = String.format("Token %s has an invalid issuer %s that does not match %s", tgt.getId(),
                claims.getIssuer(), casProperties.getServer().getPrefix());
            throw new AuthenticationException(message);
        }

        val tokenDeviceId = FunctionUtils.doUnchecked(() -> claims.getStringClaim(QRAuthenticationConstants.QR_AUTHENTICATION_DEVICE_ID));
        if (!Strings.CI.equals(tokenDeviceId, request.getDeviceId())) {
            LOGGER.warn("Request device identifier [{}] does not match the token's identifier: [{}]", request.getDeviceId(), tokenDeviceId);
            throw new AuthenticationException("Request is assigned an invalid device identifier");
        }

        if (!deviceRepository.isAuthorizedDeviceFor(request.getDeviceId(), claims.getSubject())) {
            val message = String.format("Token is not authorized for device identifier [%s]", request.getDeviceId());
            throw new AuthenticationException(message);
        }

        return QRAuthenticationTokenValidationResult.builder()
            .authentication(authentication)
            .build();
    }
}

View on GitHub (pinned to e7288fc434)