{"record":{"id":"29550e8d5ef2b2c8","repo":"immich-app/immich","slug":"cannot-rotate-an-api-key-with-permissions-you-do-n","errorCode":null,"errorMessage":"Cannot rotate an API Key with permissions you do not have","messagePattern":"Cannot rotate an API Key with permissions you do not have","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"server/src/services/api-key.service.ts","lineNumber":57,"sourceCode":"      dto.permissions &&\n      !isGranted({ requested: dto.permissions, current: auth.apiKey.permissions })\n    ) {\n      throw new BadRequestException('Cannot grant permissions you do not have');\n    }\n\n    const key = await this.apiKeyRepository.update(auth.user.id, id, { name: dto.name, permissions: dto.permissions });\n\n    return this.map(key);\n  }\n\n  async rotate(auth: AuthDto, id: string): Promise<ApiKeyCreateResponseDto> {\n    const existing = await findOrFail(() => this.apiKeyRepository.getById(auth.user.id, id), 'API Key not found');\n\n    if (\n      auth.apiKey &&\n      !isGranted({ requested: existing.permissions as Permission[], current: auth.apiKey.permissions })\n    ) {\n      throw new BadRequestException('Cannot rotate an API Key with permissions you do not have');\n    }\n\n    const token = this.cryptoRepository.randomBytesAsText(32);\n    const hashed = this.cryptoRepository.hashSha256(token);\n    const newKey = await this.apiKeyRepository.update(auth.user.id, id, { key: hashed });\n    const apiKey = this.map(newKey);\n\n    return { ...apiKey, secret: token, apiKey };\n  }\n\n  async delete(auth: AuthDto, id: string): Promise<void> {\n    const exists = await this.apiKeyRepository.getById(auth.user.id, id);\n    if (!exists) {\n      throw new BadRequestException('API Key not found');\n    }\n\n    await this.apiKeyRepository.delete(auth.user.id, id);\n  }","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/services/api-key.service.ts#L39-L75","documentation":"Raised by ApiKeyService.rotate when rotation is requested while authenticated with an API key whose permissions do not cover the (possibly renewed) permission set. Like create, it enforces that a key can never gain privileges it did not already have; the input at fault is dto.permissions (or the stored permission set) compared against auth.apiKey.permissions via isGranted.","triggerScenarios":"Thrown at server/src/services/api-key.service.ts:57 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Rotate without expanding permissions, keeping them within the authenticating key's grant","Perform the rotation authenticated as the owning user rather than through the limited API key"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}