{"record":{"id":"899acdbd3d4e265c","repo":"bitwarden/server","slug":"please-provide-a-device-identifier","errorCode":null,"errorMessage":"Please provide a device identifier","messagePattern":"Please provide a device identifier","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"src/Api/Controllers/DevicesController.cs","lineNumber":322,"sourceCode":"        }\n\n        var device = await _deviceRepository.GetByIdentifierAsync(identifier, user.Id);\n        return device != null;\n    }\n\n    [HttpPost(\"lost-trust\")]\n    public void PostLostTrust()\n    {\n        var userId = _currentContext.UserId.GetValueOrDefault();\n        if (userId == default)\n        {\n            throw new UnauthorizedAccessException();\n        }\n\n        var deviceId = _currentContext.DeviceIdentifier;\n        if (deviceId == null)\n        {\n            throw new BadRequestException(\"Please provide a device identifier\");\n        }\n\n        var deviceType = _currentContext.DeviceType;\n        if (deviceType == null)\n        {\n            throw new BadRequestException(\"Please provide a device type\");\n        }\n\n        _logger.LogError(\"User {id} has a device key, but didn't receive decryption keys for device {device} of type {deviceType}\", userId,\n            deviceId, deviceType);\n    }\n\n}\n","sourceCodeStart":304,"sourceCodeEnd":336,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/src/Api/Controllers/DevicesController.cs#L304-L336","documentation":"Thrown by POST /devices/lost-trust when the authenticated principal's device identifier is null in the request context. The endpoint exists so a client that holds a device key but never received decryption keys can log the trust-loss event; it requires the caller to be identified as a specific device. The device identifier is normally extracted from the device (access) token by middleware and surfaced on CurrentContext.","triggerScenarios":"Calling POST /devices/lost-trust authenticated as a user (with a user token) rather than a device token, or with an access token that has no device claim. UserId is present and non-default, but DeviceIdentifier on _currentContext is null.","commonSituations":"Client authenticated via a user session/OAuth token instead of a device token; a stale token minted before device claims were issued; a test harness that builds a token without the device identifier claim.","solutions":["Re-authenticate using a device (access) token that carries the device identifier claim, not a user-scoped token.","Ensure the device is registered first (POST /devices) so a device token with the identifier is issued.","Verify the Authorization header carries a device token; check CurrentContext.DeviceIdentifier is populated before calling."],"exampleFix":"// before: user token, no device claim -> DeviceIdentifier is null\n//   POST /devices/lost-trust  Authorization: Bearer <user-access-token>\n//\n// after: use the device access token obtained at device registration\nawait deviceClient.PostLostTrustAsync(); // deviceClient uses the device token","handlingStrategy":"validation","validationCode":"// Ensure the caller's token carries a device identifier before calling lost-trust\nconst deviceId = await getDeviceClaimFromToken(accessToken);\nif (!deviceId) {\n  // re-authenticate with a device token or register a device first\n  await registerDevice();\n  return;\n}\nawait devicesApi.postLostTrust();","typeGuard":"function hasDeviceIdentifier(claims) {\n  return claims?.deviceidentifier != null && claims.deviceidentifier.trim() !== '';\n}","tryCatchPattern":"try {\n  await devicesApi.postLostTrust();\n} catch (e) {\n  if (e.status === 400 && /device identifier/i.test(e.message)) {\n    // token lacks device claim: re-register / re-authenticate as a device\n    await registerDeviceAndRetry();\n  } else throw e;\n}","preventionTips":["Authenticate device-scoped endpoints with a device (access) token, not a user token.","Register the device before invoking trust endpoints so the token carries the identifier claim.","In tests, mint a token that includes the deviceidentifier claim."],"tags":["devices","auth","current-context","http-400","lost-trust"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}