@strapi/admin 5.46.1 → 5.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/dist/admin/admin/src/components/Layouts/HeaderLayout.js +51 -8
  2. package/dist/admin/admin/src/components/Layouts/HeaderLayout.js.map +1 -1
  3. package/dist/admin/admin/src/components/Layouts/HeaderLayout.mjs +52 -9
  4. package/dist/admin/admin/src/components/Layouts/HeaderLayout.mjs.map +1 -1
  5. package/dist/admin/admin/src/components/Layouts/utils/getMatchingDocLink.js +167 -0
  6. package/dist/admin/admin/src/components/Layouts/utils/getMatchingDocLink.js.map +1 -0
  7. package/dist/admin/admin/src/components/Layouts/utils/getMatchingDocLink.mjs +165 -0
  8. package/dist/admin/admin/src/components/Layouts/utils/getMatchingDocLink.mjs.map +1 -0
  9. package/dist/admin/admin/src/constants.js +8 -11
  10. package/dist/admin/admin/src/constants.js.map +1 -1
  11. package/dist/admin/admin/src/constants.mjs +8 -11
  12. package/dist/admin/admin/src/constants.mjs.map +1 -1
  13. package/dist/admin/admin/src/features/Auth.js +25 -0
  14. package/dist/admin/admin/src/features/Auth.js.map +1 -1
  15. package/dist/admin/admin/src/features/Auth.mjs +26 -1
  16. package/dist/admin/admin/src/features/Auth.mjs.map +1 -1
  17. package/dist/admin/admin/src/features/Tracking.js.map +1 -1
  18. package/dist/admin/admin/src/features/Tracking.mjs.map +1 -1
  19. package/dist/admin/admin/src/hooks/useIdleSessionLogout.js +62 -0
  20. package/dist/admin/admin/src/hooks/useIdleSessionLogout.js.map +1 -0
  21. package/dist/admin/admin/src/hooks/useIdleSessionLogout.mjs +40 -0
  22. package/dist/admin/admin/src/hooks/useIdleSessionLogout.mjs.map +1 -0
  23. package/dist/admin/admin/src/pages/Settings/constants.js +1 -2
  24. package/dist/admin/admin/src/pages/Settings/constants.js.map +1 -1
  25. package/dist/admin/admin/src/pages/Settings/constants.mjs +1 -2
  26. package/dist/admin/admin/src/pages/Settings/constants.mjs.map +1 -1
  27. package/dist/admin/admin/src/render.js +2 -1
  28. package/dist/admin/admin/src/render.js.map +1 -1
  29. package/dist/admin/admin/src/render.mjs +2 -1
  30. package/dist/admin/admin/src/render.mjs.map +1 -1
  31. package/dist/admin/admin/src/translations/en.json.js +1 -0
  32. package/dist/admin/admin/src/translations/en.json.js.map +1 -1
  33. package/dist/admin/admin/src/translations/en.json.mjs +1 -0
  34. package/dist/admin/admin/src/translations/en.json.mjs.map +1 -1
  35. package/dist/admin/admin/src/translations/sk.json.js +446 -42
  36. package/dist/admin/admin/src/translations/sk.json.js.map +1 -1
  37. package/dist/admin/admin/src/translations/sk.json.mjs +445 -43
  38. package/dist/admin/admin/src/translations/sk.json.mjs.map +1 -1
  39. package/dist/admin/admin/src/utils/baseQuery.js +5 -0
  40. package/dist/admin/admin/src/utils/baseQuery.js.map +1 -1
  41. package/dist/admin/admin/src/utils/baseQuery.mjs +6 -1
  42. package/dist/admin/admin/src/utils/baseQuery.mjs.map +1 -1
  43. package/dist/admin/admin/src/utils/getFetchClient.js +24 -0
  44. package/dist/admin/admin/src/utils/getFetchClient.js.map +1 -1
  45. package/dist/admin/admin/src/utils/getFetchClient.mjs +23 -1
  46. package/dist/admin/admin/src/utils/getFetchClient.mjs.map +1 -1
  47. package/dist/admin/admin/src/utils/jwt.js +37 -0
  48. package/dist/admin/admin/src/utils/jwt.js.map +1 -0
  49. package/dist/admin/admin/src/utils/jwt.mjs +35 -0
  50. package/dist/admin/admin/src/utils/jwt.mjs.map +1 -0
  51. package/dist/admin/index.js +2 -0
  52. package/dist/admin/index.js.map +1 -1
  53. package/dist/admin/index.mjs +1 -1
  54. package/dist/admin/src/components/Layouts/HeaderLayout.d.ts +2 -0
  55. package/dist/admin/src/components/Layouts/utils/getMatchingDocLink.d.ts +6 -0
  56. package/dist/admin/src/features/Tracking.d.ts +8 -1
  57. package/dist/admin/src/hooks/useAdminRoles.d.ts +1 -1
  58. package/dist/admin/src/hooks/useIdleSessionLogout.d.ts +33 -0
  59. package/dist/admin/src/services/admin.d.ts +6 -6
  60. package/dist/admin/src/services/contentApi.d.ts +1 -1
  61. package/dist/admin/src/services/users.d.ts +8 -8
  62. package/dist/admin/src/utils/getFetchClient.d.ts +15 -1
  63. package/dist/admin/src/utils/jwt.d.ts +15 -0
  64. package/dist/server/server/src/bootstrap.js +3 -2
  65. package/dist/server/server/src/bootstrap.js.map +1 -1
  66. package/dist/server/server/src/bootstrap.mjs +4 -3
  67. package/dist/server/server/src/bootstrap.mjs.map +1 -1
  68. package/dist/server/server/src/policies/index.js +0 -2
  69. package/dist/server/server/src/policies/index.js.map +1 -1
  70. package/dist/server/server/src/policies/index.mjs +0 -2
  71. package/dist/server/server/src/policies/index.mjs.map +1 -1
  72. package/dist/server/server/src/register.js +1 -1
  73. package/dist/server/server/src/register.js.map +1 -1
  74. package/dist/server/server/src/routes/admin-tokens.js +0 -7
  75. package/dist/server/server/src/routes/admin-tokens.js.map +1 -1
  76. package/dist/server/server/src/routes/admin-tokens.mjs +0 -7
  77. package/dist/server/server/src/routes/admin-tokens.mjs.map +1 -1
  78. package/dist/server/server/src/routes/serve-admin-panel.js +8 -1
  79. package/dist/server/server/src/routes/serve-admin-panel.js.map +1 -1
  80. package/dist/server/server/src/routes/serve-admin-panel.mjs +6 -2
  81. package/dist/server/server/src/routes/serve-admin-panel.mjs.map +1 -1
  82. package/dist/server/server/src/services/api-token.js +71 -1
  83. package/dist/server/server/src/services/api-token.js.map +1 -1
  84. package/dist/server/server/src/services/api-token.mjs +71 -2
  85. package/dist/server/server/src/services/api-token.mjs.map +1 -1
  86. package/dist/server/server/src/services/token.js +11 -0
  87. package/dist/server/server/src/services/token.js.map +1 -1
  88. package/dist/server/server/src/services/token.mjs +11 -1
  89. package/dist/server/server/src/services/token.mjs.map +1 -1
  90. package/dist/server/server/src/strategies/admin-token.js +5 -63
  91. package/dist/server/server/src/strategies/admin-token.js.map +1 -1
  92. package/dist/server/server/src/strategies/admin-token.mjs +6 -64
  93. package/dist/server/server/src/strategies/admin-token.mjs.map +1 -1
  94. package/dist/server/src/bootstrap.d.ts.map +1 -1
  95. package/dist/server/src/index.d.ts +0 -5
  96. package/dist/server/src/index.d.ts.map +1 -1
  97. package/dist/server/src/policies/index.d.ts +0 -5
  98. package/dist/server/src/policies/index.d.ts.map +1 -1
  99. package/dist/server/src/routes/admin-tokens.d.ts.map +1 -1
  100. package/dist/server/src/routes/serve-admin-panel.d.ts +2 -0
  101. package/dist/server/src/routes/serve-admin-panel.d.ts.map +1 -1
  102. package/dist/server/src/services/api-token.d.ts +15 -1
  103. package/dist/server/src/services/api-token.d.ts.map +1 -1
  104. package/dist/server/src/services/token.d.ts +7 -1
  105. package/dist/server/src/services/token.d.ts.map +1 -1
  106. package/dist/server/src/strategies/admin-token.d.ts +12 -22
  107. package/dist/server/src/strategies/admin-token.d.ts.map +1 -1
  108. package/package.json +8 -8
  109. package/dist/server/server/src/policies/isAdminTokensEnabled.js +0 -16
  110. package/dist/server/server/src/policies/isAdminTokensEnabled.js.map +0 -1
  111. package/dist/server/server/src/policies/isAdminTokensEnabled.mjs +0 -14
  112. package/dist/server/server/src/policies/isAdminTokensEnabled.mjs.map +0 -1
  113. package/dist/server/src/policies/isAdminTokensEnabled.d.ts +0 -7
  114. package/dist/server/src/policies/isAdminTokensEnabled.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"api-token.js","sources":["../../../../../server/src/services/api-token.ts"],"sourcesContent":["import crypto from 'crypto';\nimport {\n omit,\n difference,\n isNil,\n isEmpty,\n map,\n isArray,\n uniq,\n isNumber,\n differenceWith,\n isEqual,\n pick,\n prop,\n} from 'lodash/fp';\nimport type { Core, Data } from '@strapi/types';\nimport { errors } from '@strapi/utils';\nimport type {\n Update,\n ContentApiApiToken,\n ContentApiApiTokenBody,\n} from '../../../shared/contracts/api-token';\nimport type { AdminApiToken, AdminTokenBody } from '../../../shared/contracts/admin-token';\nimport type { AdminTokenOwner, AdminUser, Permission } from '../../../shared/contracts/shared';\nimport constants from './constants';\nimport { getService } from '../utils';\nimport permissionDomain from '../domain/permission';\nimport { validatePermissionsExist } from '../validation/permission';\n\ntype AnyApiToken = ContentApiApiToken | AdminApiToken;\n\nconst { SUPER_ADMIN_CODE } = constants;\n\nconst { ValidationError, NotFoundError } = errors;\n\nconst assertOwnerMatchesCallingUser = async (\n adminUserOwner: Data.ID,\n callingUser: AdminUser | undefined\n): Promise<void> => {\n if (callingUser === undefined || callingUser === null) {\n throw new ValidationError('adminUserOwner requires an authenticated admin user');\n }\n\n const ownerId = String(adminUserOwner);\n const callingUserId = String(callingUser.id);\n\n if (ownerId !== callingUserId) {\n throw new ValidationError('adminUserOwner must match the authenticated admin user');\n }\n\n const existingUser = await strapi.db.query('admin::user').findOne({\n select: ['id'],\n where: { id: callingUser.id },\n });\n\n if (existingUser === null || existingUser === undefined) {\n throw new ValidationError('adminUserOwner must reference an existing admin user');\n }\n};\n\nconst isSuperAdmin = (user: AdminUser | undefined): boolean =>\n user?.roles?.some((r) => r.code === SUPER_ADMIN_CODE) === true;\n\nconst getOwnerId = (token: AdminApiToken): string => {\n const owner = token.adminUserOwner;\n return String(typeof owner === 'object' ? owner.id : owner);\n};\n\nconst toAdminTokenOwner = (\n owner: AdminApiToken['adminUserOwner'] | null | undefined\n): Data.ID | AdminTokenOwner => {\n if (owner === null || owner === undefined) {\n throw new Error('adminUserOwner is required');\n }\n\n // Bare id\n if (typeof owner === 'number' || typeof owner === 'string') {\n return owner;\n }\n\n return {\n id: owner.id,\n firstname: owner.firstname,\n lastname: owner.lastname,\n username: owner.username,\n email: owner.email,\n };\n};\n\nconst SELECT_FIELDS = [\n 'id',\n 'kind',\n 'name',\n 'description',\n 'lastUsedAt',\n 'type',\n 'lifespan',\n 'expiresAt',\n 'createdAt',\n 'updatedAt',\n];\n\nconst POPULATE_FIELDS = ['permissions', 'adminPermissions', 'adminUserOwner'];\nconst UPDATABLE_FIELDS = ['name', 'description', 'type'] as const;\n\n// TODO: we need to ensure the permissions are actually valid registered permissions!\n\n/**\n * Assert that a token's permissions attribute is valid for its type\n */\nconst assertCustomTokenPermissionsValidity = (\n type: ContentApiApiToken['type'],\n permissions: string[] | null | undefined\n) => {\n // Ensure non-custom tokens doesn't have permissions\n if (type !== constants.API_TOKEN_TYPE.CUSTOM && !isEmpty(permissions)) {\n throw new ValidationError('Non-custom tokens should not reference permissions');\n }\n\n // Custom type tokens should always have permissions attached to them\n if (type === constants.API_TOKEN_TYPE.CUSTOM && !isArray(permissions)) {\n throw new ValidationError('Missing permissions attribute for custom token');\n }\n\n // Permissions provided for a custom type token should be valid/registered permissions UID\n if (type === constants.API_TOKEN_TYPE.CUSTOM) {\n const validPermissions = strapi.contentAPI.permissions.providers.action.keys();\n const invalidPermissions = difference(permissions, validPermissions) as string[];\n\n if (!isEmpty(invalidPermissions)) {\n throw new ValidationError(`Unknown permissions provided: ${invalidPermissions.join(', ')}`);\n }\n }\n};\n\n/**\n * Check if a token's lifespan is valid\n */\nconst isValidLifespan = (lifespan: unknown) => {\n if (isNil(lifespan)) {\n return true;\n }\n\n if (!isNumber(lifespan) || !Object.values(constants.API_TOKEN_LIFESPANS).includes(lifespan)) {\n return false;\n }\n\n return true;\n};\n\n/**\n * Assert that a token's lifespan is valid\n */\nconst assertValidLifespan = (lifespan: unknown) => {\n if (!isValidLifespan(lifespan)) {\n throw new ValidationError(\n `lifespan must be one of the following values:\n ${Object.values(constants.API_TOKEN_LIFESPANS).join(', ')}`\n );\n }\n};\n\n/** API/body shape: permission without ids/timestamps and without actionParameters (defaulted by domain when creating). */\ntype PermissionInput = Omit<Permission, 'id' | 'createdAt' | 'updatedAt' | 'actionParameters'>;\n\n/**\n * Assert that a legacy-kind token body does not carry admin-only fields\n */\nconst assertLegacyKindFields = (attributes: ContentApiApiTokenBody): void => {\n const raw = attributes as Record<string, unknown>;\n if (raw.adminPermissions !== undefined && raw.adminPermissions !== null) {\n throw new ValidationError('Legacy tokens cannot carry admin permissions');\n }\n if (raw.adminUserOwner !== undefined && raw.adminUserOwner !== null) {\n throw new ValidationError('Legacy tokens cannot have an admin user owner');\n }\n};\n\n/**\n * Assert that an admin-kind token body does not carry legacy-only fields\n */\nconst assertAdminKindFields = (attributes: AdminTokenBody): void => {\n const raw = attributes as Record<string, unknown>;\n if (raw.type !== undefined && raw.type !== null) {\n throw new ValidationError(\n 'Admin tokens cannot carry a legacy type (custom/read-only/full-access)'\n );\n }\n if (raw.permissions !== undefined && raw.permissions !== null) {\n throw new ValidationError('Admin tokens cannot carry legacy content-API permissions');\n }\n};\n\n/**\n * Assert that admin permissions are valid\n */\nconst assertAdminPermissionsValidity = async (adminPermissions?: PermissionInput[]) => {\n if (!adminPermissions || adminPermissions.length === 0) {\n return;\n }\n\n // Validate that all actions exist in the admin action provider\n const validActions = getService('permission').actionProvider.keys();\n\n for (const perm of adminPermissions) {\n if (!validActions.includes(perm.action)) {\n throw new ValidationError(`Unknown admin action: ${perm.action}`);\n }\n }\n\n // Use existing permission validation\n await validatePermissionsExist(adminPermissions as any);\n};\n\n/**\n * Enforce that every requested admin permission stays within the calling\n * user's own permission ceiling, then return the clamped permissions.\n *\n * Super-admins bypass this (they hold every permission).\n * When admin permissions are requested, an authenticated user is required (no bypass when user is missing).\n *\n * For each requested permission:\n * - action + subject must match at least one user permission\n * - properties.fields must be ⊆ user's properties.fields\n * (if the user's permission defines no fields, all fields are allowed)\n * - conditions are inherited from the user's matching permission(s);\n * the caller cannot configure conditions on their own tokens\n *\n * Returns the permissions with conditions enforced from the user's role.\n * Throws ValidationError if any permission exceeds the user's ceiling.\n *\n * Guaranteed postcondition: all returned permissions have conditions filtered to\n * registered conditions only, regardless of the user type.\n */\nconst enforceAdminPermissionsCeiling = async (\n user: AdminUser | undefined | null,\n requestedPermissions?: PermissionInput[]\n): Promise<PermissionInput[]> => {\n if (!requestedPermissions || requestedPermissions.length === 0) {\n return requestedPermissions || [];\n }\n if (user === undefined || user === null) {\n throw new ValidationError(\n 'Admin permission ceiling cannot be enforced without an authenticated user'\n );\n }\n if (isSuperAdmin(user)) {\n // Sanitize conditions even for super-admins so this function is a complete boundary.\n // createApiTokenAdminPermissions also sanitizes, but relying on that downstream\n // is fragile — any future call path that skips it would store invalid conditions.\n const { conditionProvider } = getService('permission');\n const sanitize = permissionDomain.sanitizeConditions(conditionProvider as any);\n return requestedPermissions.map((perm) => {\n const sanitized = sanitize({ ...perm, actionParameters: {} } as Permission);\n return { ...perm, conditions: sanitized.conditions };\n });\n }\n\n const userPermissions: Permission[] = await getService('permission').findUserPermissions(user);\n\n const exceeding: string[] = [];\n\n const clamped = requestedPermissions.map((requested) => {\n const requestedSubject = requested.subject || null;\n\n // Find all user permissions matching action + subject\n const matchingUserPerms = userPermissions.filter((userPerm: Permission) => {\n if (userPerm.action !== requested.action) return false;\n const userSubject = userPerm.subject || null;\n return requestedSubject === userSubject;\n });\n\n const label =\n requestedSubject !== null ? `${requested.action} on ${requestedSubject}` : requested.action;\n\n if (matchingUserPerms.length === 0) {\n exceeding.push(label);\n return requested;\n }\n\n // --- Field-level ceiling ---\n // If any matching user perm has no fields defined → all fields are allowed.\n // Otherwise, effective user fields = union of all matching perms' fields.\n const anyUserPermHasAllFields = matchingUserPerms.some(\n (p) => !p.properties?.fields || p.properties.fields.length === 0\n );\n\n const requestedFields = requested.properties?.fields;\n\n if (!anyUserPermHasAllFields) {\n const effectiveUserFields = uniq(\n matchingUserPerms.flatMap((p) => p.properties?.fields || [])\n );\n\n // When the owner is field-restricted, omitting fields would widen access to all fields.\n // Force explicit field selection so token scope can't exceed the owner's ceiling.\n if (requestedFields === undefined || requestedFields === null) {\n exceeding.push(`${label} (fields are required due to owner field restrictions)`);\n return requested;\n }\n\n if (requestedFields.length > 0) {\n const exceedingFields = requestedFields.filter((f) => !effectiveUserFields.includes(f));\n\n if (exceedingFields.length > 0) {\n exceeding.push(`${label} (fields: ${exceedingFields.join(', ')})`);\n return requested;\n }\n }\n }\n\n // --- Condition-level ceiling ---\n // Conditions are always inherited from the user's matching permission(s).\n // If any matching user perm is unconditional → token gets no conditions.\n // Otherwise → union of conditions across matching perms.\n const anyUserPermIsUnconditional = matchingUserPerms.some(\n (p) => !p.conditions || p.conditions.length === 0\n );\n\n const enforcedConditions: string[] = anyUserPermIsUnconditional\n ? []\n : (uniq(matchingUserPerms.flatMap((p) => p.conditions || [])) as string[]);\n\n return {\n ...requested,\n conditions: enforcedConditions,\n };\n });\n\n if (exceeding.length > 0) {\n throw new ValidationError(\n `Cannot assign admin permissions that exceed your own. ` +\n `Exceeding: ${exceeding.join(', ')}`\n );\n }\n\n return clamped;\n};\n\n/**\n * Create admin permissions for an API token\n */\nconst createApiTokenAdminPermissions = async (tokenId: Data.ID, permissions: PermissionInput[]) => {\n const { conditionProvider } = getService('permission');\n const sanitizeConditions = permissionDomain.sanitizeConditions(conditionProvider as any);\n\n const permissionsWithToken = permissions.map((perm) => {\n const permAsPermission = { ...perm, actionParameters: {} } as Permission;\n const sanitized = sanitizeConditions(permAsPermission);\n return permissionDomain.create({\n ...sanitized,\n apiToken: tokenId as any,\n role: null,\n } as any);\n });\n\n const createdPermissions = await getService('permission').createMany(permissionsWithToken as any);\n\n return createdPermissions;\n};\n\n/**\n * Fields to compare when checking if two permissions are equal\n */\nconst COMPARABLE_FIELDS = ['conditions', 'properties', 'subject', 'action', 'actionParameters'];\nconst pickComparableFields = pick(COMPARABLE_FIELDS);\n\n/**\n * Helper to clean JSON (remove undefined values)\n */\nconst jsonClean = <T extends object>(data: T): T => JSON.parse(JSON.stringify(data));\n\n/**\n * Compare two permissions for equality\n */\nconst arePermissionsEqual = (p1: Permission, p2: Permission): boolean => {\n if (p1.action === p2.action) {\n return isEqual(jsonClean(pickComparableFields(p1)), jsonClean(pickComparableFields(p2)));\n }\n return false;\n};\n\n/**\n * Assign admin permissions to an API token (similar to role permission assignment).\n * ceilingUser is the user whose permissions act as the ceiling — always the token owner,\n * regardless of who is making the request.\n */\nconst assignAdminPermissionsToToken = async (\n tokenId: Data.ID,\n permissions: PermissionInput[],\n ceilingUser: AdminUser\n): Promise<Permission[]> => {\n await validatePermissionsExist(permissions as any);\n const clampedPermissions = await enforceAdminPermissionsCeiling(ceilingUser, permissions);\n\n const permissionsWithToken = clampedPermissions.map((perm) =>\n permissionDomain.create({\n ...perm,\n apiToken: tokenId as any,\n role: null,\n } as any)\n );\n\n const existingPermissions = await getService('permission').findMany({\n where: { apiToken: { id: tokenId } },\n });\n\n const permissionsToAdd = differenceWith(\n arePermissionsEqual,\n permissionsWithToken,\n existingPermissions\n ) as any as Permission[];\n\n const permissionsToDelete = differenceWith(\n arePermissionsEqual,\n existingPermissions,\n permissionsWithToken\n ) as any as Permission[];\n\n if (permissionsToDelete.length > 0) {\n await getService('permission').deleteByIds(permissionsToDelete.map(prop('id')) as Data.ID[]);\n }\n\n if (permissionsToAdd.length > 0) {\n await createApiTokenAdminPermissions(tokenId, permissionsToAdd as any);\n }\n\n // Return all current permissions\n const allCurrentPermissions = await getService('permission').findMany({\n where: { apiToken: { id: tokenId } },\n });\n\n return allCurrentPermissions;\n};\n\n/**\n * Reconcile a token's admin permissions against the owner's current effective ceiling.\n *\n * Pure / sync — no DB calls. Returns two buckets:\n * toDelete – permissions that are no longer within the user's scope (action/subject missing\n * or requested fields exceed the allowed set)\n * toUpdate – permissions that are still in scope but whose conditions must be re-clamped\n * to the current union of the matching user permissions' conditions\n */\nconst reconcileTokenPermissionsToUserCeiling = (\n userPermissions: Permission[],\n tokenPermissions: Permission[]\n): { toDelete: Permission[]; toUpdate: { id: Data.ID; conditions: string[] }[] } => {\n const toDelete: Permission[] = [];\n const toUpdate: { id: Data.ID; conditions: string[] }[] = [];\n\n tokenPermissions.forEach((tokenPerm) => {\n const tokenSubject = tokenPerm.subject || null;\n\n const matchingUserPerms = userPermissions.filter(\n (userPerm) =>\n userPerm.action === tokenPerm.action && (userPerm.subject || null) === tokenSubject\n );\n\n if (matchingUserPerms.length === 0) {\n toDelete.push(tokenPerm);\n return;\n }\n\n // Field-level ceiling check (mirrors enforceAdminPermissionsCeiling)\n const anyUserPermHasAllFields = matchingUserPerms.some(\n (p) => !p.properties?.fields || p.properties.fields.length === 0\n );\n const tokenFields = tokenPerm.properties?.fields;\n\n const fieldCeilingExceeded =\n !anyUserPermHasAllFields &&\n tokenFields !== undefined &&\n tokenFields !== null &&\n tokenFields.length > 0 &&\n (() => {\n const effectiveUserFields = uniq(\n matchingUserPerms.flatMap((p) => p.properties?.fields || [])\n );\n return tokenFields.some((f) => !effectiveUserFields.includes(f));\n })();\n\n if (fieldCeilingExceeded) {\n toDelete.push(tokenPerm);\n return;\n }\n\n // Condition: force conditions to be the ones of the user permission(s)\n const anyUserPermIsUnconditional = matchingUserPerms.some(\n (p) => !p.conditions || p.conditions.length === 0\n );\n const enforcedConditions: string[] = anyUserPermIsUnconditional\n ? []\n : (uniq(matchingUserPerms.flatMap((p) => p.conditions || [])) as string[]);\n\n const currentConditions: string[] = (tokenPerm.conditions as string[]) || [];\n const conditionsChanged =\n enforcedConditions.length !== currentConditions.length ||\n enforcedConditions.some((c) => !currentConditions.includes(c));\n\n if (conditionsChanged) {\n toUpdate.push({ id: tokenPerm.id as Data.ID, conditions: enforcedConditions });\n }\n });\n\n return { toDelete, toUpdate };\n};\n\n/**\n * Re-sync all admin token permissions for a given user against their current effective ceiling.\n *\n * Skips super-admins (no ceiling). For each admin token owned by the user:\n * - Deletes permissions that are no longer within the user's scope\n * - Updates conditions on permissions whose conditions have drifted from the role's current set\n */\nconst syncApiTokenPermissionsForUser = async (userId: Data.ID): Promise<void> => {\n const user = await strapi.db.query('admin::user').findOne({\n where: { id: userId },\n populate: ['roles'],\n });\n\n if (user === null || user === undefined) return;\n if (isSuperAdmin(user as AdminUser)) return;\n\n const userEffectivePermissions: Permission[] = await getService('permission').findUserPermissions(\n user as AdminUser\n );\n\n const tokens = await strapi.db.query('admin::api-token').findMany({\n where: { kind: 'admin', adminUserOwner: { id: userId } },\n populate: ['adminPermissions'],\n });\n\n const tokensWithPermissions = tokens.filter(\n (token: { adminPermissions?: Permission[] }) =>\n Array.isArray(token.adminPermissions) && token.adminPermissions.length > 0\n );\n\n for (const token of tokensWithPermissions) {\n const tokenPermissions: Permission[] = token.adminPermissions as Permission[];\n\n const { toDelete, toUpdate } = reconcileTokenPermissionsToUserCeiling(\n userEffectivePermissions,\n tokenPermissions\n );\n\n if (toDelete.length > 0) {\n await getService('permission').deleteByIds(toDelete.map((p) => p.id as Data.ID));\n }\n\n for (const { id, conditions } of toUpdate) {\n await strapi.db.query('admin::permission').update({ where: { id }, data: { conditions } });\n }\n }\n};\n\n/**\n * Re-sync admin token permissions for all admin users who hold a given role.\n * Called after role permissions are updated.\n */\nconst syncApiTokenPermissionsForRole = async (roleId: Data.ID): Promise<void> => {\n const users = await strapi.db.query('admin::user').findMany({\n where: { roles: { id: roleId } },\n populate: ['roles'],\n });\n\n await Promise.allSettled(users.map((user) => syncApiTokenPermissionsForUser(user.id as Data.ID)));\n};\n\n/**\n * Flatten a token's database permissions objects to an array of strings\n */\nconst flattenTokenPermissions = (permissions: { action: string }[] | undefined): string[] => {\n return isArray(permissions) ? map('action', permissions) : [];\n};\n\ntype WhereParams = {\n id?: string | number;\n name?: string;\n lastUsedAt?: number;\n description?: string;\n accessKey?: string;\n kind?: 'content-api' | 'admin';\n};\n\ntype GetByOptions = {\n includeDecryptedKey?: boolean;\n};\n\n/**\n * Get a token.\n * By default the plaintext accessKey is NOT included.\n * Pass { includeDecryptedKey: true } to decrypt and return it (owner-only paths).\n */\nconst getBy = async (\n whereParams: WhereParams = {},\n options: GetByOptions = {}\n): Promise<AnyApiToken | null> => {\n if (Object.keys(whereParams).length === 0) {\n return null;\n }\n\n const { includeDecryptedKey = false } = options;\n\n const selectFields = includeDecryptedKey ? [...SELECT_FIELDS, 'encryptedKey'] : SELECT_FIELDS;\n\n const token = await strapi.db.query('admin::api-token').findOne({\n select: selectFields,\n populate: POPULATE_FIELDS,\n where: whereParams,\n });\n\n if (!token) {\n return token;\n }\n\n // Tokens created before kind introduction case: force kind to be content-api\n const computedKind = token.kind ?? 'content-api';\n\n const result = omit(\n ['accessKey', 'encryptedKey', 'type', 'permissions', 'adminPermissions', 'adminUserOwner'],\n token\n );\n\n if (computedKind === 'content-api') {\n Object.assign(result, {\n kind: 'content-api',\n type: token.type,\n permissions: flattenTokenPermissions(token.permissions),\n });\n } else if (computedKind === 'admin') {\n Object.assign(result, {\n kind: 'admin',\n adminPermissions: token.adminPermissions,\n adminUserOwner: toAdminTokenOwner(token.adminUserOwner),\n });\n }\n\n if (includeDecryptedKey && token.encryptedKey) {\n Object.assign(result, { accessKey: getService('encryption').decrypt(token.encryptedKey) });\n }\n\n return result as AnyApiToken;\n};\n\n/**\n * Check if token exists\n */\nconst exists = async (whereParams: WhereParams = {}): Promise<boolean> => {\n const apiToken = await getBy(whereParams);\n\n return !!apiToken;\n};\n\n/**\n * Return a secure sha512 hash of an accessKey\n */\nconst hash = (accessKey: string) => {\n const apiTokenCfg = strapi.config.get<Core.Config.Admin['apiToken']>('admin.apiToken');\n const salt = apiTokenCfg.salt;\n\n return crypto.createHmac('sha512', salt).update(accessKey).digest('hex');\n};\n\nconst getExpirationFields = (lifespan: AnyApiToken['lifespan']) => {\n // it must be nil or a finite number >= 0\n const isValidNumber = isNumber(lifespan) && Number.isFinite(lifespan) && lifespan > 0;\n if (!isValidNumber && !isNil(lifespan)) {\n throw new ValidationError('lifespan must be a positive number or null');\n }\n\n return {\n lifespan: lifespan ?? null,\n expiresAt: lifespan ? Date.now() + lifespan : null,\n };\n};\n\n/**\n * Create a token and its permissions\n */\nconst create = async <K extends AnyApiToken['kind']>(\n attributes: { kind: K } & (ContentApiApiTokenBody | AdminTokenBody),\n callingUser?: AdminUser\n): Promise<\n K extends 'content-api' ? ContentApiApiToken : K extends 'admin' ? AdminApiToken : AnyApiToken\n> => {\n const encryptionService = getService('encryption');\n const accessKey = crypto.randomBytes(128).toString('hex');\n const encryptedKey = encryptionService.encrypt(accessKey);\n\n assertValidLifespan(attributes.lifespan);\n\n if (attributes.kind === 'content-api') {\n const castedContentApiApiTokenBody = attributes as ContentApiApiTokenBody;\n assertLegacyKindFields(castedContentApiApiTokenBody);\n assertCustomTokenPermissionsValidity(\n castedContentApiApiTokenBody.type,\n castedContentApiApiTokenBody.permissions\n );\n\n // content api tokens have no owner\n const apiToken = await strapi.db.query('admin::api-token').create({\n select: SELECT_FIELDS,\n populate: POPULATE_FIELDS,\n data: {\n ...(omit(['permissions', 'adminPermissions', 'adminUserOwner'], attributes) as object),\n accessKey: hash(accessKey),\n encryptedKey,\n adminUserOwner: null,\n ...getExpirationFields(castedContentApiApiTokenBody.lifespan ?? null),\n },\n });\n\n const result: ContentApiApiToken = { ...apiToken, accessKey };\n\n // If this is a custom type token, create the related content-API permissions\n if (castedContentApiApiTokenBody.type === constants.API_TOKEN_TYPE.CUSTOM) {\n // TODO: createMany doesn't seem to create relation properly, implement a better way rather than a ton of queries\n await Promise.all(\n uniq(castedContentApiApiTokenBody.permissions).map((action) =>\n strapi.db.query('admin::api-token-permission').create({\n data: { action, token: apiToken },\n })\n )\n );\n\n const currentPermissions = await strapi.db\n .query('admin::api-token')\n .load(apiToken, 'permissions');\n\n if (currentPermissions) {\n Object.assign(result, { permissions: flattenTokenPermissions(currentPermissions) });\n }\n }\n\n // Casted to any to avoid complex type duplication\n return omit(['adminPermissions', 'adminUserOwner'], result) as any;\n }\n\n // kind === 'admin'\n assertAdminKindFields(attributes);\n const castedAdminTokenBody = attributes as AdminTokenBody;\n await assertAdminPermissionsValidity(castedAdminTokenBody.adminPermissions);\n const clampedAdminPermissions = await enforceAdminPermissionsCeiling(\n callingUser,\n castedAdminTokenBody.adminPermissions\n );\n\n // Owner: when explicitly provided, it must match the caller.\n // When omitted, always defaults to the calling user (including super admins).\n let ownerId: Data.ID;\n if (\n castedAdminTokenBody.adminUserOwner !== undefined &&\n castedAdminTokenBody.adminUserOwner !== null\n ) {\n await assertOwnerMatchesCallingUser(castedAdminTokenBody.adminUserOwner, callingUser);\n ownerId = castedAdminTokenBody.adminUserOwner;\n } else {\n if (callingUser === undefined || callingUser === null) {\n throw new ValidationError('Creating an admin token requires an authenticated admin user');\n }\n ownerId = callingUser.id as Data.ID;\n }\n\n const apiToken = await strapi.db.query('admin::api-token').create({\n select: SELECT_FIELDS,\n populate: POPULATE_FIELDS,\n data: {\n ...(omit(['permissions', 'adminPermissions', 'adminUserOwner'], attributes) as object),\n accessKey: hash(accessKey),\n encryptedKey,\n adminUserOwner: ownerId,\n ...getExpirationFields(castedAdminTokenBody.lifespan ?? null),\n },\n });\n\n const result = { ...apiToken, accessKey } as AnyApiToken;\n\n // Handle admin permissions (using ceiling-clamped permissions with inherited conditions)\n if (clampedAdminPermissions.length > 0) {\n await createApiTokenAdminPermissions(apiToken.id, clampedAdminPermissions);\n\n const currentAdminPermissions = await strapi.db\n .query('admin::api-token')\n .load(apiToken, 'adminPermissions');\n\n if (currentAdminPermissions) {\n Object.assign(result, { adminPermissions: currentAdminPermissions });\n }\n }\n\n // Casted to any to avoid complex type duplication\n return {\n ...(omit(['permissions'], result) as object),\n adminUserOwner: toAdminTokenOwner((result as AdminApiToken).adminUserOwner),\n } as any;\n};\n\nconst regenerate = async (id: string | number): Promise<ContentApiApiToken | AdminApiToken> => {\n const accessKey = crypto.randomBytes(128).toString('hex');\n const encryptionService = getService('encryption');\n const encryptedKey = encryptionService.encrypt(accessKey);\n\n const apiToken: AnyApiToken = await strapi.db.query('admin::api-token').update({\n select: ['id', 'accessKey', 'kind'],\n where: { id },\n data: {\n accessKey: hash(accessKey),\n encryptedKey,\n },\n });\n\n if (!apiToken) {\n throw new NotFoundError('The provided token id does not exist');\n }\n\n return {\n ...apiToken,\n kind: (apiToken.kind ?? 'content-api') as AnyApiToken['kind'],\n accessKey,\n } as any;\n};\n\nconst checkSaltIsDefined = () => {\n const apiTokenCfg = strapi.config.get<Core.Config.Admin['apiToken']>('admin.apiToken');\n if (!apiTokenCfg?.salt) {\n // TODO V5: stop reading API_TOKEN_SALT\n if (process.env.API_TOKEN_SALT) {\n process.emitWarning(`[deprecated] In future versions, Strapi will stop reading directly from the environment variable API_TOKEN_SALT. Please set apiToken.salt in config/admin.js instead.\nFor security reasons, keep storing the secret in an environment variable and use env() to read it in config/admin.js (ex: \\`apiToken: { salt: env('API_TOKEN_SALT') }\\`). See https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/configurations/optional/environment.html#configuration-using-environment-variables.`);\n\n strapi.config.set('admin.apiToken.salt', process.env.API_TOKEN_SALT);\n } else {\n throw new Error(\n `Missing apiToken.salt. Please set apiToken.salt in config/admin.js (ex: you can generate one using Node with \\`crypto.randomBytes(16).toString('base64')\\`).\nFor security reasons, prefer storing the secret in an environment variable and read it in config/admin.js. See https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/configurations/optional/environment.html#configuration-using-environment-variables.`\n );\n }\n }\n};\n\n/**\n * Return a list of tokens visible to the calling user.\n * Super-admins see all tokens; regular admins see only ownerless tokens and their own.\n */\nconst list = async <K extends AnyApiToken['kind']>(\n callingUser: AdminUser,\n { filter }: { filter?: { kind?: K } } = {}\n): Promise<\n Array<\n K extends 'content-api' ? ContentApiApiToken : K extends 'admin' ? AdminApiToken : AnyApiToken\n >\n> => {\n const ownershipWhere = isSuperAdmin(callingUser)\n ? {}\n : { $or: [{ adminUserOwner: null }, { adminUserOwner: { id: callingUser.id } }] };\n\n // Tokens without a persisted kind are content-api tokens (pre-migration rows).\n let kindWhere: Record<string, unknown> = {};\n if (filter?.kind === 'content-api') {\n kindWhere = { $or: [{ kind: 'content-api' }, { kind: { $null: true } }] };\n } else if (filter?.kind !== undefined) {\n kindWhere = { kind: filter.kind };\n }\n\n const where = { ...ownershipWhere, ...kindWhere };\n\n const tokens = await strapi.db.query('admin::api-token').findMany({\n select: SELECT_FIELDS,\n populate: POPULATE_FIELDS,\n orderBy: { name: 'ASC' },\n where,\n });\n\n if (!tokens) {\n return tokens;\n }\n\n return tokens.map((token) =>\n token.kind === null || token.kind === 'content-api'\n ? omit(['adminPermissions', 'adminUserOwner'], {\n ...token,\n // Tokens created before kind introduction case: force kind to be content-api\n kind: 'content-api',\n permissions: flattenTokenPermissions(token.permissions),\n })\n : ({\n ...(omit(['permissions'], token) as object),\n adminUserOwner:\n token.adminUserOwner !== null && token.adminUserOwner !== undefined\n ? toAdminTokenOwner(token.adminUserOwner)\n : null,\n } as any)\n );\n};\n\n/**\n * Revoke (delete) a token\n */\nconst revoke = async (id: string | number): Promise<AnyApiToken> => {\n const token = await strapi.db.query('admin::api-token').findOne({\n where: { id },\n select: ['id'],\n populate: ['adminPermissions'],\n });\n\n if (token !== null && token !== undefined) {\n const permissionIds = ((token.adminPermissions as Array<{ id: Data.ID }>) ?? [])\n .map((p) => p.id)\n .filter((permId) => permId !== null && permId !== undefined);\n\n if (permissionIds.length > 0) {\n await getService('permission').deleteByIds(permissionIds);\n }\n }\n\n const deletedToken = await strapi.db\n .query('admin::api-token')\n .delete({ select: SELECT_FIELDS, populate: POPULATE_FIELDS, where: { id } });\n\n if (deletedToken === null || deletedToken === undefined) {\n return deletedToken;\n }\n\n if (deletedToken.kind === 'admin') {\n return {\n ...deletedToken,\n adminUserOwner: toAdminTokenOwner(deletedToken.adminUserOwner),\n };\n }\n\n // content-api tokens (including legacy null-kind rows): normalise shape\n return omit(['adminPermissions', 'adminUserOwner'], {\n ...deletedToken,\n kind: 'content-api' as const,\n permissions: flattenTokenPermissions(deletedToken.permissions),\n }) as ContentApiApiToken;\n};\n\n/**\n * Retrieve a token by id\n */\nconst getById = async (id: string | number, options?: GetByOptions) => {\n return getBy({ id }, options);\n};\n\n/**\n * Retrieve a token by name\n */\nconst getByName = async (name: string, options?: GetByOptions) => {\n return getBy({ name }, options);\n};\n\n/**\n * Update a token and its permissions\n */\nconst update = async (\n id: string | number,\n attributes: Update.Request['body']\n): Promise<AnyApiToken> => {\n const originalToken = await strapi.db\n .query('admin::api-token')\n .findOne({ select: SELECT_FIELDS, populate: ['adminUserOwner'], where: { id } });\n\n if (!originalToken) {\n throw new NotFoundError('Token not found');\n }\n\n const raw = attributes as Record<string, unknown>;\n\n // kind is immutable after creation.\n // Null-kind rows are legacy content-api tokens — treat null and 'content-api' as the same\n // effective value so that clients echoing back the normalised kind from a GET don't get rejected.\n const effectiveStoredKind = originalToken.kind ?? 'content-api';\n if (raw.kind !== undefined && raw.kind !== null && raw.kind !== effectiveStoredKind) {\n throw new ValidationError('kind is immutable after creation');\n }\n\n let clampedAdminPermissions: PermissionInput[] | undefined;\n let tokenOwnerUser: AdminUser | undefined;\n\n if (originalToken.kind === null || originalToken.kind === 'content-api') {\n assertLegacyKindFields(attributes as ContentApiApiTokenBody);\n\n const incomingType = raw.type as ContentApiApiToken['type'] | undefined;\n const incomingPermissions = raw.permissions as string[] | null | undefined;\n const resolvedType = incomingType ?? (originalToken.type as ContentApiApiToken['type']);\n const changingTypeToCustom =\n incomingType === constants.API_TOKEN_TYPE.CUSTOM &&\n originalToken.type !== constants.API_TOKEN_TYPE.CUSTOM;\n\n // Only re-validate if permissions or type are being changed\n if (incomingPermissions !== undefined || changingTypeToCustom) {\n assertCustomTokenPermissionsValidity(\n resolvedType,\n incomingPermissions ?? (originalToken.permissions as string[])\n );\n }\n } else if (originalToken.kind === 'admin') {\n assertAdminKindFields(attributes as AdminTokenBody);\n\n const incomingAdminPermissions = raw.adminPermissions as PermissionInput[] | undefined;\n if (incomingAdminPermissions !== undefined) {\n await assertAdminPermissionsValidity(incomingAdminPermissions);\n\n // Ceiling is always the owner's permissions, not the calling user's.\n // A super admin editing another user's token must not overflow that user's scope.\n const ownerId = getOwnerId(originalToken as AdminApiToken);\n const resolvedOwner = await getService('user').findOne(ownerId);\n if (resolvedOwner === null || resolvedOwner === undefined) {\n throw new ValidationError('Token owner no longer exists');\n }\n tokenOwnerUser = resolvedOwner;\n clampedAdminPermissions = await enforceAdminPermissionsCeiling(\n tokenOwnerUser,\n incomingAdminPermissions\n );\n }\n\n const incomingAdminUserOwner = raw.adminUserOwner;\n if (incomingAdminUserOwner !== undefined) {\n // Owner is immutable; the provided value must match the existing one\n const existingOwner = originalToken.adminUserOwner;\n const existingOwnerId =\n existingOwner === null || existingOwner === undefined\n ? null\n : String(typeof existingOwner === 'object' ? existingOwner.id : existingOwner);\n const requestedOwnerId =\n incomingAdminUserOwner === null ? null : String(incomingAdminUserOwner);\n\n if (requestedOwnerId !== existingOwnerId) {\n throw new ValidationError('adminUserOwner cannot be changed on update');\n }\n }\n }\n\n const baseData = pick(UPDATABLE_FIELDS, attributes) as Record<string, unknown>;\n\n // Migrate legacy null-kind rows to the explicit value on first write\n if (originalToken.kind === null) {\n baseData.kind = 'content-api';\n }\n\n const updatedToken = await strapi.db.query('admin::api-token').update({\n select: SELECT_FIELDS,\n where: { id },\n data: baseData,\n });\n\n if (originalToken.kind === null || originalToken.kind === 'content-api') {\n const incomingPermissions = raw.permissions as string[] | null | undefined;\n\n // custom tokens need to have their permissions updated as well\n if (\n updatedToken.type === constants.API_TOKEN_TYPE.CUSTOM &&\n incomingPermissions !== undefined\n ) {\n const currentPermissionsResult = await strapi.db\n .query('admin::api-token')\n .load(updatedToken, 'permissions');\n\n const currentPermissions = map('action', currentPermissionsResult || []);\n const newPermissions = uniq(incomingPermissions || []);\n\n const actionsToDelete = difference(currentPermissions, newPermissions);\n const actionsToAdd = difference(newPermissions, currentPermissions);\n\n // TODO: improve efficiency here\n await Promise.all(\n actionsToDelete.map((action) =>\n strapi.db.query('admin::api-token-permission').delete({\n where: { action, token: id },\n })\n )\n );\n\n // TODO: improve efficiency here\n await Promise.all(\n actionsToAdd.map((action) =>\n strapi.db.query('admin::api-token-permission').create({\n data: { action, token: id },\n })\n )\n );\n }\n // if type is not custom, make sure any old permissions get removed\n else if (updatedToken.type !== constants.API_TOKEN_TYPE.CUSTOM) {\n await strapi.db.query('admin::api-token-permission').delete({\n where: { token: id },\n });\n }\n\n const permissionsFromDb = await strapi.db\n .query('admin::api-token')\n .load(updatedToken, 'permissions');\n\n return {\n ...updatedToken,\n permissions: permissionsFromDb ? permissionsFromDb.map((p: any) => p.action) : undefined,\n } as AnyApiToken;\n }\n\n // kind === 'admin'\n if (clampedAdminPermissions !== undefined) {\n if (tokenOwnerUser === undefined) {\n throw new ValidationError('Updating admin permissions requires a resolved token owner');\n }\n await assignAdminPermissionsToToken(id, clampedAdminPermissions, tokenOwnerUser);\n }\n\n const adminPermissionsFromDb = await strapi.db\n .query('admin::api-token')\n .load(updatedToken, 'adminPermissions');\n\n const adminUserOwnerFromDb = await strapi.db\n .query('admin::api-token')\n .load(updatedToken, 'adminUserOwner');\n\n return {\n ...updatedToken,\n adminPermissions: adminPermissionsFromDb || [],\n adminUserOwner: toAdminTokenOwner(adminUserOwnerFromDb),\n } as AnyApiToken;\n};\n\nconst count = async (where = {}): Promise<number> => {\n return strapi.db.query('admin::api-token').count({ where });\n};\n\n/**\n * Delete all admin API tokens owned by the given user, including their associated admin permissions.\n * Called when the owner user is deleted so tokens don't linger with a dangling owner FK.\n */\nconst deleteAdminTokensForUser = async (userId: Data.ID): Promise<void> => {\n const tokens = await strapi.db.query('admin::api-token').findMany({\n where: { kind: 'admin', adminUserOwner: { id: userId } },\n select: ['id'],\n populate: ['adminPermissions'],\n });\n\n for (const token of tokens) {\n const permissionIds = ((token.adminPermissions as Array<{ id: Data.ID }>) ?? [])\n .map((p) => p.id)\n .filter((id) => id !== null && id !== undefined);\n\n if (permissionIds.length > 0) {\n await getService('permission').deleteByIds(permissionIds);\n }\n\n await strapi.db.query('admin::api-token').delete({ where: { id: token.id } });\n }\n};\n\n// -------------------------------------------------------------------------\n// Service interfaces\n// -------------------------------------------------------------------------\n\ninterface SharedTokenMethods {\n hash(accessKey: string): string;\n checkSaltIsDefined(): void;\n /** Kind-agnostic lookup by hashed access key — used by the auth strategy. */\n getByAccessKey(accessKeyHash: string, options?: GetByOptions): Promise<AnyApiToken | null>;\n /** Total count across all kinds. */\n countAll(where?: object): Promise<number>;\n reconcileTokenPermissionsToUserCeiling(\n userPermissions: Permission[],\n tokenPermissions: Permission[]\n ): { toDelete: Permission[]; toUpdate: { id: Data.ID; conditions: string[] }[] };\n}\n\nexport interface ContentApiTokenService extends SharedTokenMethods {\n create(attributes: ContentApiApiTokenBody, callingUser?: AdminUser): Promise<ContentApiApiToken>;\n list(callingUser: AdminUser): Promise<ContentApiApiToken[]>;\n getById(id: string | number, options?: GetByOptions): Promise<ContentApiApiToken | null>;\n getByName(name: string, options?: GetByOptions): Promise<ContentApiApiToken | null>;\n update(\n id: string | number,\n attributes: Partial<ContentApiApiTokenBody>\n ): Promise<ContentApiApiToken>;\n revoke(id: string | number): Promise<ContentApiApiToken>;\n regenerate(id: string | number): Promise<ContentApiApiToken>;\n exists(where: WhereParams): Promise<boolean>;\n count(where?: object): Promise<number>;\n}\n\nexport interface AdminTokenService extends SharedTokenMethods {\n create(attributes: AdminTokenBody, callingUser: AdminUser): Promise<AdminApiToken>;\n list(callingUser: AdminUser): Promise<AdminApiToken[]>;\n getById(id: string | number, options?: GetByOptions): Promise<AdminApiToken | null>;\n getByName(name: string, options?: GetByOptions): Promise<AdminApiToken | null>;\n update(id: string | number, attributes: Partial<AdminTokenBody>): Promise<AdminApiToken>;\n revoke(id: string | number): Promise<AdminApiToken>;\n regenerate(id: string | number): Promise<AdminApiToken>;\n exists(where: WhereParams): Promise<boolean>;\n count(where?: object): Promise<number>;\n assignAdminPermissionsToToken(\n tokenId: Data.ID,\n permissions: PermissionInput[],\n ceilingUser: AdminUser\n ): Promise<Permission[]>;\n syncPermissionsForUser(userId: Data.ID): Promise<void>;\n syncPermissionsForRole(roleId: Data.ID): Promise<void>;\n deleteTokensForUser(userId: Data.ID): Promise<void>;\n}\n\n// -------------------------------------------------------------------------\n// Factory\n// -------------------------------------------------------------------------\n\nfunction createTokenService(kind: 'content-api'): ContentApiTokenService;\nfunction createTokenService(kind: 'admin'): AdminTokenService;\nfunction createTokenService(\n kind: 'content-api' | 'admin'\n): ContentApiTokenService | AdminTokenService {\n const shared: SharedTokenMethods = {\n hash,\n checkSaltIsDefined,\n getByAccessKey: (accessKeyHash, options) => getBy({ accessKey: accessKeyHash }, options),\n countAll: count,\n reconcileTokenPermissionsToUserCeiling,\n };\n\n if (kind === 'content-api') {\n const svc: ContentApiTokenService = {\n ...shared,\n create: (attributes: ContentApiApiTokenBody, callingUser?: AdminUser) =>\n create({ ...attributes, kind: 'content-api' }, callingUser) as Promise<ContentApiApiToken>,\n list: (callingUser: AdminUser) =>\n list(callingUser, { filter: { kind: 'content-api' } }) as Promise<ContentApiApiToken[]>,\n getById: (id: string | number, options?: GetByOptions) =>\n getBy(\n {\n $and: [{ id }, { $or: [{ kind: 'content-api' }, { kind: { $null: true } }] }],\n } as any,\n options\n ) as Promise<ContentApiApiToken | null>,\n getByName: (name: string, options?: GetByOptions) =>\n getBy(\n {\n $and: [{ name }, { $or: [{ kind: 'content-api' }, { kind: { $null: true } }] }],\n } as any,\n options\n ) as Promise<ContentApiApiToken | null>,\n update: (id: string | number, attributes: Partial<ContentApiApiTokenBody>) =>\n update(id, attributes) as Promise<ContentApiApiToken>,\n revoke: (id: string | number) => revoke(id) as Promise<ContentApiApiToken>,\n regenerate: (id: string | number) => regenerate(id) as Promise<ContentApiApiToken>,\n exists,\n count,\n };\n return svc;\n }\n\n const svc: AdminTokenService = {\n ...shared,\n create: (attributes: AdminTokenBody, callingUser: AdminUser) =>\n create({ ...attributes, kind: 'admin' }, callingUser) as Promise<AdminApiToken>,\n list: (callingUser: AdminUser) =>\n list(callingUser, { filter: { kind: 'admin' } }) as Promise<AdminApiToken[]>,\n getById: (id: string | number, options?: GetByOptions) =>\n getBy({ id, kind: 'admin' }, options) as Promise<AdminApiToken | null>,\n getByName: (name: string, options?: GetByOptions) =>\n getBy({ name, kind: 'admin' }, options) as Promise<AdminApiToken | null>,\n update: (id: string | number, attributes: Partial<AdminTokenBody>) =>\n update(id, attributes) as Promise<AdminApiToken>,\n revoke: (id: string | number) => revoke(id) as Promise<AdminApiToken>,\n regenerate: (id: string | number) => regenerate(id) as Promise<AdminApiToken>,\n exists,\n count,\n assignAdminPermissionsToToken,\n syncPermissionsForUser: syncApiTokenPermissionsForUser,\n syncPermissionsForRole: syncApiTokenPermissionsForRole,\n deleteTokensForUser: deleteAdminTokensForUser,\n };\n return svc;\n}\n\nexport type { GetByOptions };\n\nexport {\n createTokenService,\n create,\n count,\n regenerate,\n exists,\n checkSaltIsDefined,\n hash,\n list,\n revoke,\n getById,\n update,\n getByName,\n getBy,\n assignAdminPermissionsToToken,\n enforceAdminPermissionsCeiling,\n reconcileTokenPermissionsToUserCeiling,\n syncApiTokenPermissionsForUser,\n syncApiTokenPermissionsForRole,\n deleteAdminTokensForUser,\n};\n"],"names":["SUPER_ADMIN_CODE","constants","ValidationError","NotFoundError","errors","assertOwnerMatchesCallingUser","adminUserOwner","callingUser","undefined","ownerId","String","callingUserId","id","existingUser","strapi","db","query","findOne","select","where","isSuperAdmin","user","roles","some","r","code","getOwnerId","token","owner","toAdminTokenOwner","Error","firstname","lastname","username","email","SELECT_FIELDS","POPULATE_FIELDS","UPDATABLE_FIELDS","assertCustomTokenPermissionsValidity","type","permissions","API_TOKEN_TYPE","CUSTOM","isEmpty","isArray","validPermissions","contentAPI","providers","action","keys","invalidPermissions","difference","join","isValidLifespan","lifespan","isNil","isNumber","Object","values","API_TOKEN_LIFESPANS","includes","assertValidLifespan","assertLegacyKindFields","attributes","raw","adminPermissions","assertAdminKindFields","assertAdminPermissionsValidity","length","validActions","getService","actionProvider","perm","validatePermissionsExist","enforceAdminPermissionsCeiling","requestedPermissions","conditionProvider","sanitize","permissionDomain","sanitizeConditions","map","sanitized","actionParameters","conditions","userPermissions","findUserPermissions","exceeding","clamped","requested","requestedSubject","subject","matchingUserPerms","filter","userPerm","userSubject","label","push","anyUserPermHasAllFields","p","properties","fields","requestedFields","effectiveUserFields","uniq","flatMap","exceedingFields","f","anyUserPermIsUnconditional","enforcedConditions","createApiTokenAdminPermissions","tokenId","permissionsWithToken","permAsPermission","create","apiToken","role","createdPermissions","createMany","COMPARABLE_FIELDS","pickComparableFields","pick","jsonClean","data","JSON","parse","stringify","arePermissionsEqual","p1","p2","isEqual","assignAdminPermissionsToToken","ceilingUser","clampedPermissions","existingPermissions","findMany","permissionsToAdd","differenceWith","permissionsToDelete","deleteByIds","prop","allCurrentPermissions","reconcileTokenPermissionsToUserCeiling","tokenPermissions","toDelete","toUpdate","forEach","tokenPerm","tokenSubject","tokenFields","fieldCeilingExceeded","currentConditions","conditionsChanged","c","syncApiTokenPermissionsForUser","userId","populate","userEffectivePermissions","tokens","kind","tokensWithPermissions","Array","update","syncApiTokenPermissionsForRole","roleId","users","Promise","allSettled","flattenTokenPermissions","getBy","whereParams","options","includeDecryptedKey","selectFields","computedKind","result","omit","assign","encryptedKey","accessKey","decrypt","exists","hash","apiTokenCfg","config","get","salt","crypto","createHmac","digest","getExpirationFields","isValidNumber","Number","isFinite","expiresAt","Date","now","encryptionService","randomBytes","toString","encrypt","castedContentApiApiTokenBody","all","currentPermissions","load","castedAdminTokenBody","clampedAdminPermissions","currentAdminPermissions","regenerate","checkSaltIsDefined","process","env","API_TOKEN_SALT","emitWarning","set","list","ownershipWhere","$or","kindWhere","$null","orderBy","name","revoke","permissionIds","permId","deletedToken","delete","originalToken","effectiveStoredKind","tokenOwnerUser","incomingType","incomingPermissions","resolvedType","changingTypeToCustom","incomingAdminPermissions","resolvedOwner","incomingAdminUserOwner","existingOwner","existingOwnerId","requestedOwnerId","baseData","updatedToken","currentPermissionsResult","newPermissions","actionsToDelete","actionsToAdd","permissionsFromDb","adminPermissionsFromDb","adminUserOwnerFromDb","count","deleteAdminTokensForUser","createTokenService","shared","getByAccessKey","accessKeyHash","countAll","svc","getById","$and","getByName","syncPermissionsForUser","syncPermissionsForRole","deleteTokensForUser"],"mappings":"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"}
1
+ {"version":3,"file":"api-token.js","sources":["../../../../../server/src/services/api-token.ts"],"sourcesContent":["import crypto from 'crypto';\nimport {\n omit,\n difference,\n isNil,\n isEmpty,\n map,\n isArray,\n uniq,\n isNumber,\n differenceWith,\n isEqual,\n pick,\n prop,\n} from 'lodash/fp';\nimport type { Core, Data } from '@strapi/types';\nimport { errors } from '@strapi/utils';\nimport type { Ability } from '@casl/ability';\nimport type {\n Update,\n ContentApiApiToken,\n ContentApiApiTokenBody,\n} from '../../../shared/contracts/api-token';\nimport type { AdminApiToken, AdminTokenBody } from '../../../shared/contracts/admin-token';\nimport type { AdminTokenOwner, AdminUser, Permission } from '../../../shared/contracts/shared';\nimport constants from './constants';\nimport { getService } from '../utils';\nimport permissionDomain from '../domain/permission';\nimport { validatePermissionsExist } from '../validation/permission';\nimport { checkExpiry, updateLastUsedAt } from '../strategies/api-token-utils';\n\ntype AnyApiToken = ContentApiApiToken | AdminApiToken;\n\nconst { SUPER_ADMIN_CODE } = constants;\n\nconst { ValidationError, NotFoundError, UnauthorizedError } = errors;\n\nexport type AdminTokenAuthenticationResult =\n | { authenticated: false; error?: InstanceType<typeof UnauthorizedError> }\n | { authenticated: true; credentials: AdminApiToken; user: AdminUser; ability: Ability };\n\nconst assertOwnerMatchesCallingUser = async (\n adminUserOwner: Data.ID,\n callingUser: AdminUser | undefined\n): Promise<void> => {\n if (callingUser === undefined || callingUser === null) {\n throw new ValidationError('adminUserOwner requires an authenticated admin user');\n }\n\n const ownerId = String(adminUserOwner);\n const callingUserId = String(callingUser.id);\n\n if (ownerId !== callingUserId) {\n throw new ValidationError('adminUserOwner must match the authenticated admin user');\n }\n\n const existingUser = await strapi.db.query('admin::user').findOne({\n select: ['id'],\n where: { id: callingUser.id },\n });\n\n if (existingUser === null || existingUser === undefined) {\n throw new ValidationError('adminUserOwner must reference an existing admin user');\n }\n};\n\nconst isSuperAdmin = (user: AdminUser | undefined): boolean =>\n user?.roles?.some((r) => r.code === SUPER_ADMIN_CODE) === true;\n\nconst getOwnerId = (token: AdminApiToken): string => {\n const owner = token.adminUserOwner;\n return String(typeof owner === 'object' ? owner.id : owner);\n};\n\nconst resolveAdminTokenOwnerId = (token: AdminApiToken): Data.ID | null => {\n const owner = token.adminUserOwner;\n\n if (owner === null || owner === undefined) {\n return null;\n }\n\n if (typeof owner === 'object') {\n return owner.id;\n }\n\n return owner;\n};\n\nconst toAdminTokenOwner = (\n owner: AdminApiToken['adminUserOwner'] | null | undefined\n): Data.ID | AdminTokenOwner => {\n if (owner === null || owner === undefined) {\n throw new Error('adminUserOwner is required');\n }\n\n // Bare id\n if (typeof owner === 'number' || typeof owner === 'string') {\n return owner;\n }\n\n return {\n id: owner.id,\n firstname: owner.firstname,\n lastname: owner.lastname,\n username: owner.username,\n email: owner.email,\n };\n};\n\nconst SELECT_FIELDS = [\n 'id',\n 'kind',\n 'name',\n 'description',\n 'lastUsedAt',\n 'type',\n 'lifespan',\n 'expiresAt',\n 'createdAt',\n 'updatedAt',\n];\n\nconst POPULATE_FIELDS = ['permissions', 'adminPermissions', 'adminUserOwner'];\nconst UPDATABLE_FIELDS = ['name', 'description', 'type'] as const;\n\n// TODO: we need to ensure the permissions are actually valid registered permissions!\n\n/**\n * Assert that a token's permissions attribute is valid for its type\n */\nconst assertCustomTokenPermissionsValidity = (\n type: ContentApiApiToken['type'],\n permissions: string[] | null | undefined\n) => {\n // Ensure non-custom tokens doesn't have permissions\n if (type !== constants.API_TOKEN_TYPE.CUSTOM && !isEmpty(permissions)) {\n throw new ValidationError('Non-custom tokens should not reference permissions');\n }\n\n // Custom type tokens should always have permissions attached to them\n if (type === constants.API_TOKEN_TYPE.CUSTOM && !isArray(permissions)) {\n throw new ValidationError('Missing permissions attribute for custom token');\n }\n\n // Permissions provided for a custom type token should be valid/registered permissions UID\n if (type === constants.API_TOKEN_TYPE.CUSTOM) {\n const validPermissions = strapi.contentAPI.permissions.providers.action.keys();\n const invalidPermissions = difference(permissions, validPermissions) as string[];\n\n if (!isEmpty(invalidPermissions)) {\n throw new ValidationError(`Unknown permissions provided: ${invalidPermissions.join(', ')}`);\n }\n }\n};\n\n/**\n * Check if a token's lifespan is valid\n */\nconst isValidLifespan = (lifespan: unknown) => {\n if (isNil(lifespan)) {\n return true;\n }\n\n if (!isNumber(lifespan) || !Object.values(constants.API_TOKEN_LIFESPANS).includes(lifespan)) {\n return false;\n }\n\n return true;\n};\n\n/**\n * Assert that a token's lifespan is valid\n */\nconst assertValidLifespan = (lifespan: unknown) => {\n if (!isValidLifespan(lifespan)) {\n throw new ValidationError(\n `lifespan must be one of the following values:\n ${Object.values(constants.API_TOKEN_LIFESPANS).join(', ')}`\n );\n }\n};\n\n/** API/body shape: permission without ids/timestamps and without actionParameters (defaulted by domain when creating). */\ntype PermissionInput = Omit<Permission, 'id' | 'createdAt' | 'updatedAt' | 'actionParameters'>;\n\n/**\n * Assert that a legacy-kind token body does not carry admin-only fields\n */\nconst assertLegacyKindFields = (attributes: ContentApiApiTokenBody): void => {\n const raw = attributes as Record<string, unknown>;\n if (raw.adminPermissions !== undefined && raw.adminPermissions !== null) {\n throw new ValidationError('Legacy tokens cannot carry admin permissions');\n }\n if (raw.adminUserOwner !== undefined && raw.adminUserOwner !== null) {\n throw new ValidationError('Legacy tokens cannot have an admin user owner');\n }\n};\n\n/**\n * Assert that an admin-kind token body does not carry legacy-only fields\n */\nconst assertAdminKindFields = (attributes: AdminTokenBody): void => {\n const raw = attributes as Record<string, unknown>;\n if (raw.type !== undefined && raw.type !== null) {\n throw new ValidationError(\n 'Admin tokens cannot carry a legacy type (custom/read-only/full-access)'\n );\n }\n if (raw.permissions !== undefined && raw.permissions !== null) {\n throw new ValidationError('Admin tokens cannot carry legacy content-API permissions');\n }\n};\n\n/**\n * Assert that admin permissions are valid\n */\nconst assertAdminPermissionsValidity = async (adminPermissions?: PermissionInput[]) => {\n if (!adminPermissions || adminPermissions.length === 0) {\n return;\n }\n\n // Validate that all actions exist in the admin action provider\n const validActions = getService('permission').actionProvider.keys();\n\n for (const perm of adminPermissions) {\n if (!validActions.includes(perm.action)) {\n throw new ValidationError(`Unknown admin action: ${perm.action}`);\n }\n }\n\n // Use existing permission validation\n await validatePermissionsExist(adminPermissions as any);\n};\n\n/**\n * Enforce that every requested admin permission stays within the calling\n * user's own permission ceiling, then return the clamped permissions.\n *\n * Super-admins bypass this (they hold every permission).\n * When admin permissions are requested, an authenticated user is required (no bypass when user is missing).\n *\n * For each requested permission:\n * - action + subject must match at least one user permission\n * - properties.fields must be ⊆ user's properties.fields\n * (if the user's permission defines no fields, all fields are allowed)\n * - conditions are inherited from the user's matching permission(s);\n * the caller cannot configure conditions on their own tokens\n *\n * Returns the permissions with conditions enforced from the user's role.\n * Throws ValidationError if any permission exceeds the user's ceiling.\n *\n * Guaranteed postcondition: all returned permissions have conditions filtered to\n * registered conditions only, regardless of the user type.\n */\nconst enforceAdminPermissionsCeiling = async (\n user: AdminUser | undefined | null,\n requestedPermissions?: PermissionInput[]\n): Promise<PermissionInput[]> => {\n if (!requestedPermissions || requestedPermissions.length === 0) {\n return requestedPermissions || [];\n }\n if (user === undefined || user === null) {\n throw new ValidationError(\n 'Admin permission ceiling cannot be enforced without an authenticated user'\n );\n }\n if (isSuperAdmin(user)) {\n // Sanitize conditions even for super-admins so this function is a complete boundary.\n // createApiTokenAdminPermissions also sanitizes, but relying on that downstream\n // is fragile — any future call path that skips it would store invalid conditions.\n const { conditionProvider } = getService('permission');\n const sanitize = permissionDomain.sanitizeConditions(conditionProvider as any);\n return requestedPermissions.map((perm) => {\n const sanitized = sanitize({ ...perm, actionParameters: {} } as Permission);\n return { ...perm, conditions: sanitized.conditions };\n });\n }\n\n const userPermissions: Permission[] = await getService('permission').findUserPermissions(user);\n\n const exceeding: string[] = [];\n\n const clamped = requestedPermissions.map((requested) => {\n const requestedSubject = requested.subject || null;\n\n // Find all user permissions matching action + subject\n const matchingUserPerms = userPermissions.filter((userPerm: Permission) => {\n if (userPerm.action !== requested.action) return false;\n const userSubject = userPerm.subject || null;\n return requestedSubject === userSubject;\n });\n\n const label =\n requestedSubject !== null ? `${requested.action} on ${requestedSubject}` : requested.action;\n\n if (matchingUserPerms.length === 0) {\n exceeding.push(label);\n return requested;\n }\n\n // --- Field-level ceiling ---\n // If any matching user perm has no fields defined → all fields are allowed.\n // Otherwise, effective user fields = union of all matching perms' fields.\n const anyUserPermHasAllFields = matchingUserPerms.some(\n (p) => !p.properties?.fields || p.properties.fields.length === 0\n );\n\n const requestedFields = requested.properties?.fields;\n\n if (!anyUserPermHasAllFields) {\n const effectiveUserFields = uniq(\n matchingUserPerms.flatMap((p) => p.properties?.fields || [])\n );\n\n // When the owner is field-restricted, omitting fields would widen access to all fields.\n // Force explicit field selection so token scope can't exceed the owner's ceiling.\n if (requestedFields === undefined || requestedFields === null) {\n exceeding.push(`${label} (fields are required due to owner field restrictions)`);\n return requested;\n }\n\n if (requestedFields.length > 0) {\n const exceedingFields = requestedFields.filter((f) => !effectiveUserFields.includes(f));\n\n if (exceedingFields.length > 0) {\n exceeding.push(`${label} (fields: ${exceedingFields.join(', ')})`);\n return requested;\n }\n }\n }\n\n // --- Condition-level ceiling ---\n // Conditions are always inherited from the user's matching permission(s).\n // If any matching user perm is unconditional → token gets no conditions.\n // Otherwise → union of conditions across matching perms.\n const anyUserPermIsUnconditional = matchingUserPerms.some(\n (p) => !p.conditions || p.conditions.length === 0\n );\n\n const enforcedConditions: string[] = anyUserPermIsUnconditional\n ? []\n : (uniq(matchingUserPerms.flatMap((p) => p.conditions || [])) as string[]);\n\n return {\n ...requested,\n conditions: enforcedConditions,\n };\n });\n\n if (exceeding.length > 0) {\n throw new ValidationError(\n `Cannot assign admin permissions that exceed your own. ` +\n `Exceeding: ${exceeding.join(', ')}`\n );\n }\n\n return clamped;\n};\n\n/**\n * Create admin permissions for an API token\n */\nconst createApiTokenAdminPermissions = async (tokenId: Data.ID, permissions: PermissionInput[]) => {\n const { conditionProvider } = getService('permission');\n const sanitizeConditions = permissionDomain.sanitizeConditions(conditionProvider as any);\n\n const permissionsWithToken = permissions.map((perm) => {\n const permAsPermission = { ...perm, actionParameters: {} } as Permission;\n const sanitized = sanitizeConditions(permAsPermission);\n return permissionDomain.create({\n ...sanitized,\n apiToken: tokenId as any,\n role: null,\n } as any);\n });\n\n const createdPermissions = await getService('permission').createMany(permissionsWithToken as any);\n\n return createdPermissions;\n};\n\n/**\n * Fields to compare when checking if two permissions are equal\n */\nconst COMPARABLE_FIELDS = ['conditions', 'properties', 'subject', 'action', 'actionParameters'];\nconst pickComparableFields = pick(COMPARABLE_FIELDS);\n\n/**\n * Helper to clean JSON (remove undefined values)\n */\nconst jsonClean = <T extends object>(data: T): T => JSON.parse(JSON.stringify(data));\n\n/**\n * Compare two permissions for equality\n */\nconst arePermissionsEqual = (p1: Permission, p2: Permission): boolean => {\n if (p1.action === p2.action) {\n return isEqual(jsonClean(pickComparableFields(p1)), jsonClean(pickComparableFields(p2)));\n }\n return false;\n};\n\n/**\n * Assign admin permissions to an API token (similar to role permission assignment).\n * ceilingUser is the user whose permissions act as the ceiling — always the token owner,\n * regardless of who is making the request.\n */\nconst assignAdminPermissionsToToken = async (\n tokenId: Data.ID,\n permissions: PermissionInput[],\n ceilingUser: AdminUser\n): Promise<Permission[]> => {\n await validatePermissionsExist(permissions as any);\n const clampedPermissions = await enforceAdminPermissionsCeiling(ceilingUser, permissions);\n\n const permissionsWithToken = clampedPermissions.map((perm) =>\n permissionDomain.create({\n ...perm,\n apiToken: tokenId as any,\n role: null,\n } as any)\n );\n\n const existingPermissions = await getService('permission').findMany({\n where: { apiToken: { id: tokenId } },\n });\n\n const permissionsToAdd = differenceWith(\n arePermissionsEqual,\n permissionsWithToken,\n existingPermissions\n ) as any as Permission[];\n\n const permissionsToDelete = differenceWith(\n arePermissionsEqual,\n existingPermissions,\n permissionsWithToken\n ) as any as Permission[];\n\n if (permissionsToDelete.length > 0) {\n await getService('permission').deleteByIds(permissionsToDelete.map(prop('id')) as Data.ID[]);\n }\n\n if (permissionsToAdd.length > 0) {\n await createApiTokenAdminPermissions(tokenId, permissionsToAdd as any);\n }\n\n // Return all current permissions\n const allCurrentPermissions = await getService('permission').findMany({\n where: { apiToken: { id: tokenId } },\n });\n\n return allCurrentPermissions;\n};\n\n/**\n * Reconcile a token's admin permissions against the owner's current effective ceiling.\n *\n * Pure / sync — no DB calls. Returns two buckets:\n * toDelete – permissions that are no longer within the user's scope (action/subject missing\n * or requested fields exceed the allowed set)\n * toUpdate – permissions that are still in scope but whose conditions must be re-clamped\n * to the current union of the matching user permissions' conditions\n */\nconst reconcileTokenPermissionsToUserCeiling = (\n userPermissions: Permission[],\n tokenPermissions: Permission[]\n): { toDelete: Permission[]; toUpdate: { id: Data.ID; conditions: string[] }[] } => {\n const toDelete: Permission[] = [];\n const toUpdate: { id: Data.ID; conditions: string[] }[] = [];\n\n tokenPermissions.forEach((tokenPerm) => {\n const tokenSubject = tokenPerm.subject || null;\n\n const matchingUserPerms = userPermissions.filter(\n (userPerm) =>\n userPerm.action === tokenPerm.action && (userPerm.subject || null) === tokenSubject\n );\n\n if (matchingUserPerms.length === 0) {\n toDelete.push(tokenPerm);\n return;\n }\n\n // Field-level ceiling check (mirrors enforceAdminPermissionsCeiling)\n const anyUserPermHasAllFields = matchingUserPerms.some(\n (p) => !p.properties?.fields || p.properties.fields.length === 0\n );\n const tokenFields = tokenPerm.properties?.fields;\n\n const fieldCeilingExceeded =\n !anyUserPermHasAllFields &&\n tokenFields !== undefined &&\n tokenFields !== null &&\n tokenFields.length > 0 &&\n (() => {\n const effectiveUserFields = uniq(\n matchingUserPerms.flatMap((p) => p.properties?.fields || [])\n );\n return tokenFields.some((f) => !effectiveUserFields.includes(f));\n })();\n\n if (fieldCeilingExceeded) {\n toDelete.push(tokenPerm);\n return;\n }\n\n // Condition: force conditions to be the ones of the user permission(s)\n const anyUserPermIsUnconditional = matchingUserPerms.some(\n (p) => !p.conditions || p.conditions.length === 0\n );\n const enforcedConditions: string[] = anyUserPermIsUnconditional\n ? []\n : (uniq(matchingUserPerms.flatMap((p) => p.conditions || [])) as string[]);\n\n const currentConditions: string[] = (tokenPerm.conditions as string[]) || [];\n const conditionsChanged =\n enforcedConditions.length !== currentConditions.length ||\n enforcedConditions.some((c) => !currentConditions.includes(c));\n\n if (conditionsChanged) {\n toUpdate.push({ id: tokenPerm.id as Data.ID, conditions: enforcedConditions });\n }\n });\n\n return { toDelete, toUpdate };\n};\n\n/**\n * Re-sync all admin token permissions for a given user against their current effective ceiling.\n *\n * Skips super-admins (no ceiling). For each admin token owned by the user:\n * - Deletes permissions that are no longer within the user's scope\n * - Updates conditions on permissions whose conditions have drifted from the role's current set\n */\nconst syncApiTokenPermissionsForUser = async (userId: Data.ID): Promise<void> => {\n const user = await strapi.db.query('admin::user').findOne({\n where: { id: userId },\n populate: ['roles'],\n });\n\n if (user === null || user === undefined) return;\n if (isSuperAdmin(user as AdminUser)) return;\n\n const userEffectivePermissions: Permission[] = await getService('permission').findUserPermissions(\n user as AdminUser\n );\n\n const tokens = await strapi.db.query('admin::api-token').findMany({\n where: { kind: 'admin', adminUserOwner: { id: userId } },\n populate: ['adminPermissions'],\n });\n\n const tokensWithPermissions = tokens.filter(\n (token: { adminPermissions?: Permission[] }) =>\n Array.isArray(token.adminPermissions) && token.adminPermissions.length > 0\n );\n\n for (const token of tokensWithPermissions) {\n const tokenPermissions: Permission[] = token.adminPermissions as Permission[];\n\n const { toDelete, toUpdate } = reconcileTokenPermissionsToUserCeiling(\n userEffectivePermissions,\n tokenPermissions\n );\n\n if (toDelete.length > 0) {\n await getService('permission').deleteByIds(toDelete.map((p) => p.id as Data.ID));\n }\n\n for (const { id, conditions } of toUpdate) {\n await strapi.db.query('admin::permission').update({ where: { id }, data: { conditions } });\n }\n }\n};\n\n/**\n * Re-sync admin token permissions for all admin users who hold a given role.\n * Called after role permissions are updated.\n */\nconst syncApiTokenPermissionsForRole = async (roleId: Data.ID): Promise<void> => {\n const users = await strapi.db.query('admin::user').findMany({\n where: { roles: { id: roleId } },\n populate: ['roles'],\n });\n\n await Promise.allSettled(users.map((user) => syncApiTokenPermissionsForUser(user.id as Data.ID)));\n};\n\n/**\n * Flatten a token's database permissions objects to an array of strings\n */\nconst flattenTokenPermissions = (permissions: { action: string }[] | undefined): string[] => {\n return isArray(permissions) ? map('action', permissions) : [];\n};\n\ntype WhereParams = {\n id?: string | number;\n name?: string;\n lastUsedAt?: number;\n description?: string;\n accessKey?: string;\n kind?: 'content-api' | 'admin';\n};\n\ntype GetByOptions = {\n includeDecryptedKey?: boolean;\n};\n\n/**\n * Get a token.\n * By default the plaintext accessKey is NOT included.\n * Pass { includeDecryptedKey: true } to decrypt and return it (owner-only paths).\n */\nconst getBy = async (\n whereParams: WhereParams = {},\n options: GetByOptions = {}\n): Promise<AnyApiToken | null> => {\n if (Object.keys(whereParams).length === 0) {\n return null;\n }\n\n const { includeDecryptedKey = false } = options;\n\n const selectFields = includeDecryptedKey ? [...SELECT_FIELDS, 'encryptedKey'] : SELECT_FIELDS;\n\n const token = await strapi.db.query('admin::api-token').findOne({\n select: selectFields,\n populate: POPULATE_FIELDS,\n where: whereParams,\n });\n\n if (!token) {\n return token;\n }\n\n // Tokens created before kind introduction case: force kind to be content-api\n const computedKind = token.kind ?? 'content-api';\n\n const result = omit(\n ['accessKey', 'encryptedKey', 'type', 'permissions', 'adminPermissions', 'adminUserOwner'],\n token\n );\n\n if (computedKind === 'content-api') {\n Object.assign(result, {\n kind: 'content-api',\n type: token.type,\n permissions: flattenTokenPermissions(token.permissions),\n });\n } else if (computedKind === 'admin') {\n Object.assign(result, {\n kind: 'admin',\n adminPermissions: token.adminPermissions,\n adminUserOwner: toAdminTokenOwner(token.adminUserOwner),\n });\n }\n\n if (includeDecryptedKey && token.encryptedKey) {\n Object.assign(result, { accessKey: getService('encryption').decrypt(token.encryptedKey) });\n }\n\n return result as AnyApiToken;\n};\n\n/**\n * Check if token exists\n */\nconst exists = async (whereParams: WhereParams = {}): Promise<boolean> => {\n const apiToken = await getBy(whereParams);\n\n return !!apiToken;\n};\n\n/**\n * Return a secure sha512 hash of an accessKey\n */\nconst hash = (accessKey: string) => {\n const apiTokenCfg = strapi.config.get<Core.Config.Admin['apiToken']>('admin.apiToken');\n const salt = apiTokenCfg.salt;\n\n return crypto.createHmac('sha512', salt).update(accessKey).digest('hex');\n};\n\nconst authenticateAdminToken = async (\n accessToken: string\n): Promise<AdminTokenAuthenticationResult> => {\n const apiToken = (await getBy({ accessKey: hash(accessToken) })) as AdminApiToken | null;\n\n if (apiToken === null || apiToken === undefined) {\n return { authenticated: false };\n }\n\n if (apiToken.kind !== 'admin') {\n return { authenticated: false };\n }\n\n const expiryError = checkExpiry(apiToken);\n if (expiryError !== null) {\n return { authenticated: false, error: expiryError };\n }\n\n const ownerId = resolveAdminTokenOwnerId(apiToken);\n if (ownerId === null) {\n return { authenticated: false, error: new UnauthorizedError('Token owner not found') };\n }\n\n const user = await strapi.db\n .query('admin::user')\n .findOne({ where: { id: ownerId }, populate: ['roles'] });\n\n if (user === null || user === undefined) {\n return { authenticated: false, error: new UnauthorizedError('Token owner not found') };\n }\n\n if (user.isActive !== true || user.blocked === true) {\n return { authenticated: false, error: new UnauthorizedError('Token owner is deactivated') };\n }\n\n await updateLastUsedAt(apiToken);\n\n const ability = await getService('permission').engine.generateTokenAbility(\n apiToken.adminPermissions ?? [],\n user\n );\n\n return { authenticated: true, credentials: apiToken, user, ability };\n};\n\nconst getExpirationFields = (lifespan: AnyApiToken['lifespan']) => {\n // it must be nil or a finite number >= 0\n const isValidNumber = isNumber(lifespan) && Number.isFinite(lifespan) && lifespan > 0;\n if (!isValidNumber && !isNil(lifespan)) {\n throw new ValidationError('lifespan must be a positive number or null');\n }\n\n return {\n lifespan: lifespan ?? null,\n expiresAt: lifespan ? Date.now() + lifespan : null,\n };\n};\n\n/**\n * Create a token and its permissions\n */\nconst create = async <K extends AnyApiToken['kind']>(\n attributes: { kind: K } & (ContentApiApiTokenBody | AdminTokenBody),\n callingUser?: AdminUser\n): Promise<\n K extends 'content-api' ? ContentApiApiToken : K extends 'admin' ? AdminApiToken : AnyApiToken\n> => {\n const encryptionService = getService('encryption');\n const accessKey = crypto.randomBytes(128).toString('hex');\n const encryptedKey = encryptionService.encrypt(accessKey);\n\n assertValidLifespan(attributes.lifespan);\n\n if (attributes.kind === 'content-api') {\n const castedContentApiApiTokenBody = attributes as ContentApiApiTokenBody;\n assertLegacyKindFields(castedContentApiApiTokenBody);\n assertCustomTokenPermissionsValidity(\n castedContentApiApiTokenBody.type,\n castedContentApiApiTokenBody.permissions\n );\n\n // content api tokens have no owner\n const apiToken = await strapi.db.query('admin::api-token').create({\n select: SELECT_FIELDS,\n populate: POPULATE_FIELDS,\n data: {\n ...(omit(['permissions', 'adminPermissions', 'adminUserOwner'], attributes) as object),\n accessKey: hash(accessKey),\n encryptedKey,\n adminUserOwner: null,\n ...getExpirationFields(castedContentApiApiTokenBody.lifespan ?? null),\n },\n });\n\n const result: ContentApiApiToken = { ...apiToken, accessKey };\n\n // If this is a custom type token, create the related content-API permissions\n if (castedContentApiApiTokenBody.type === constants.API_TOKEN_TYPE.CUSTOM) {\n // TODO: createMany doesn't seem to create relation properly, implement a better way rather than a ton of queries\n await Promise.all(\n uniq(castedContentApiApiTokenBody.permissions).map((action) =>\n strapi.db.query('admin::api-token-permission').create({\n data: { action, token: apiToken },\n })\n )\n );\n\n const currentPermissions = await strapi.db\n .query('admin::api-token')\n .load(apiToken, 'permissions');\n\n if (currentPermissions) {\n Object.assign(result, { permissions: flattenTokenPermissions(currentPermissions) });\n }\n }\n\n // Casted to any to avoid complex type duplication\n return omit(['adminPermissions', 'adminUserOwner'], result) as any;\n }\n\n // kind === 'admin'\n assertAdminKindFields(attributes);\n const castedAdminTokenBody = attributes as AdminTokenBody;\n await assertAdminPermissionsValidity(castedAdminTokenBody.adminPermissions);\n const clampedAdminPermissions = await enforceAdminPermissionsCeiling(\n callingUser,\n castedAdminTokenBody.adminPermissions\n );\n\n // Owner: when explicitly provided, it must match the caller.\n // When omitted, always defaults to the calling user (including super admins).\n let ownerId: Data.ID;\n if (\n castedAdminTokenBody.adminUserOwner !== undefined &&\n castedAdminTokenBody.adminUserOwner !== null\n ) {\n await assertOwnerMatchesCallingUser(castedAdminTokenBody.adminUserOwner, callingUser);\n ownerId = castedAdminTokenBody.adminUserOwner;\n } else {\n if (callingUser === undefined || callingUser === null) {\n throw new ValidationError('Creating an admin token requires an authenticated admin user');\n }\n ownerId = callingUser.id as Data.ID;\n }\n\n const apiToken = await strapi.db.query('admin::api-token').create({\n select: SELECT_FIELDS,\n populate: POPULATE_FIELDS,\n data: {\n ...(omit(['permissions', 'adminPermissions', 'adminUserOwner'], attributes) as object),\n accessKey: hash(accessKey),\n encryptedKey,\n adminUserOwner: ownerId,\n ...getExpirationFields(castedAdminTokenBody.lifespan ?? null),\n },\n });\n\n const result = { ...apiToken, accessKey } as AnyApiToken;\n\n // Handle admin permissions (using ceiling-clamped permissions with inherited conditions)\n if (clampedAdminPermissions.length > 0) {\n await createApiTokenAdminPermissions(apiToken.id, clampedAdminPermissions);\n\n const currentAdminPermissions = await strapi.db\n .query('admin::api-token')\n .load(apiToken, 'adminPermissions');\n\n if (currentAdminPermissions) {\n Object.assign(result, { adminPermissions: currentAdminPermissions });\n }\n }\n\n // Casted to any to avoid complex type duplication\n return {\n ...(omit(['permissions'], result) as object),\n adminUserOwner: toAdminTokenOwner((result as AdminApiToken).adminUserOwner),\n } as any;\n};\n\nconst regenerate = async (id: string | number): Promise<ContentApiApiToken | AdminApiToken> => {\n const accessKey = crypto.randomBytes(128).toString('hex');\n const encryptionService = getService('encryption');\n const encryptedKey = encryptionService.encrypt(accessKey);\n\n const apiToken: AnyApiToken = await strapi.db.query('admin::api-token').update({\n select: ['id', 'accessKey', 'kind'],\n where: { id },\n data: {\n accessKey: hash(accessKey),\n encryptedKey,\n },\n });\n\n if (!apiToken) {\n throw new NotFoundError('The provided token id does not exist');\n }\n\n return {\n ...apiToken,\n kind: (apiToken.kind ?? 'content-api') as AnyApiToken['kind'],\n accessKey,\n } as any;\n};\n\nconst checkSaltIsDefined = () => {\n const apiTokenCfg = strapi.config.get<Core.Config.Admin['apiToken']>('admin.apiToken');\n if (!apiTokenCfg?.salt) {\n // TODO V5: stop reading API_TOKEN_SALT\n if (process.env.API_TOKEN_SALT) {\n process.emitWarning(`[deprecated] In future versions, Strapi will stop reading directly from the environment variable API_TOKEN_SALT. Please set apiToken.salt in config/admin.js instead.\nFor security reasons, keep storing the secret in an environment variable and use env() to read it in config/admin.js (ex: \\`apiToken: { salt: env('API_TOKEN_SALT') }\\`). See https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/configurations/optional/environment.html#configuration-using-environment-variables.`);\n\n strapi.config.set('admin.apiToken.salt', process.env.API_TOKEN_SALT);\n } else {\n throw new Error(\n `Missing apiToken.salt. Please set apiToken.salt in config/admin.js (ex: you can generate one using Node with \\`crypto.randomBytes(16).toString('base64')\\`).\nFor security reasons, prefer storing the secret in an environment variable and read it in config/admin.js. See https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/configurations/optional/environment.html#configuration-using-environment-variables.`\n );\n }\n }\n};\n\n/**\n * Return a list of tokens visible to the calling user.\n * Super-admins see all tokens; regular admins see only ownerless tokens and their own.\n */\nconst list = async <K extends AnyApiToken['kind']>(\n callingUser: AdminUser,\n { filter }: { filter?: { kind?: K } } = {}\n): Promise<\n Array<\n K extends 'content-api' ? ContentApiApiToken : K extends 'admin' ? AdminApiToken : AnyApiToken\n >\n> => {\n const ownershipWhere = isSuperAdmin(callingUser)\n ? {}\n : { $or: [{ adminUserOwner: null }, { adminUserOwner: { id: callingUser.id } }] };\n\n // Tokens without a persisted kind are content-api tokens (pre-migration rows).\n let kindWhere: Record<string, unknown> = {};\n if (filter?.kind === 'content-api') {\n kindWhere = { $or: [{ kind: 'content-api' }, { kind: { $null: true } }] };\n } else if (filter?.kind !== undefined) {\n kindWhere = { kind: filter.kind };\n }\n\n const where = { ...ownershipWhere, ...kindWhere };\n\n const tokens = await strapi.db.query('admin::api-token').findMany({\n select: SELECT_FIELDS,\n populate: POPULATE_FIELDS,\n orderBy: { name: 'ASC' },\n where,\n });\n\n if (!tokens) {\n return tokens;\n }\n\n return tokens.map((token) =>\n token.kind === null || token.kind === 'content-api'\n ? omit(['adminPermissions', 'adminUserOwner'], {\n ...token,\n // Tokens created before kind introduction case: force kind to be content-api\n kind: 'content-api',\n permissions: flattenTokenPermissions(token.permissions),\n })\n : ({\n ...(omit(['permissions'], token) as object),\n adminUserOwner:\n token.adminUserOwner !== null && token.adminUserOwner !== undefined\n ? toAdminTokenOwner(token.adminUserOwner)\n : null,\n } as any)\n );\n};\n\n/**\n * Revoke (delete) a token\n */\nconst revoke = async (id: string | number): Promise<AnyApiToken> => {\n const token = await strapi.db.query('admin::api-token').findOne({\n where: { id },\n select: ['id'],\n populate: ['adminPermissions'],\n });\n\n if (token !== null && token !== undefined) {\n const permissionIds = ((token.adminPermissions as Array<{ id: Data.ID }>) ?? [])\n .map((p) => p.id)\n .filter((permId) => permId !== null && permId !== undefined);\n\n if (permissionIds.length > 0) {\n await getService('permission').deleteByIds(permissionIds);\n }\n }\n\n const deletedToken = await strapi.db\n .query('admin::api-token')\n .delete({ select: SELECT_FIELDS, populate: POPULATE_FIELDS, where: { id } });\n\n if (deletedToken === null || deletedToken === undefined) {\n return deletedToken;\n }\n\n if (deletedToken.kind === 'admin') {\n return {\n ...deletedToken,\n adminUserOwner: toAdminTokenOwner(deletedToken.adminUserOwner),\n };\n }\n\n // content-api tokens (including legacy null-kind rows): normalise shape\n return omit(['adminPermissions', 'adminUserOwner'], {\n ...deletedToken,\n kind: 'content-api' as const,\n permissions: flattenTokenPermissions(deletedToken.permissions),\n }) as ContentApiApiToken;\n};\n\n/**\n * Retrieve a token by id\n */\nconst getById = async (id: string | number, options?: GetByOptions) => {\n return getBy({ id }, options);\n};\n\n/**\n * Retrieve a token by name\n */\nconst getByName = async (name: string, options?: GetByOptions) => {\n return getBy({ name }, options);\n};\n\n/**\n * Update a token and its permissions\n */\nconst update = async (\n id: string | number,\n attributes: Update.Request['body']\n): Promise<AnyApiToken> => {\n const originalToken = await strapi.db\n .query('admin::api-token')\n .findOne({ select: SELECT_FIELDS, populate: ['adminUserOwner'], where: { id } });\n\n if (!originalToken) {\n throw new NotFoundError('Token not found');\n }\n\n const raw = attributes as Record<string, unknown>;\n\n // kind is immutable after creation.\n // Null-kind rows are legacy content-api tokens — treat null and 'content-api' as the same\n // effective value so that clients echoing back the normalised kind from a GET don't get rejected.\n const effectiveStoredKind = originalToken.kind ?? 'content-api';\n if (raw.kind !== undefined && raw.kind !== null && raw.kind !== effectiveStoredKind) {\n throw new ValidationError('kind is immutable after creation');\n }\n\n let clampedAdminPermissions: PermissionInput[] | undefined;\n let tokenOwnerUser: AdminUser | undefined;\n\n if (originalToken.kind === null || originalToken.kind === 'content-api') {\n assertLegacyKindFields(attributes as ContentApiApiTokenBody);\n\n const incomingType = raw.type as ContentApiApiToken['type'] | undefined;\n const incomingPermissions = raw.permissions as string[] | null | undefined;\n const resolvedType = incomingType ?? (originalToken.type as ContentApiApiToken['type']);\n const changingTypeToCustom =\n incomingType === constants.API_TOKEN_TYPE.CUSTOM &&\n originalToken.type !== constants.API_TOKEN_TYPE.CUSTOM;\n\n // Only re-validate if permissions or type are being changed\n if (incomingPermissions !== undefined || changingTypeToCustom) {\n assertCustomTokenPermissionsValidity(\n resolvedType,\n incomingPermissions ?? (originalToken.permissions as string[])\n );\n }\n } else if (originalToken.kind === 'admin') {\n assertAdminKindFields(attributes as AdminTokenBody);\n\n const incomingAdminPermissions = raw.adminPermissions as PermissionInput[] | undefined;\n if (incomingAdminPermissions !== undefined) {\n await assertAdminPermissionsValidity(incomingAdminPermissions);\n\n // Ceiling is always the owner's permissions, not the calling user's.\n // A super admin editing another user's token must not overflow that user's scope.\n const ownerId = getOwnerId(originalToken as AdminApiToken);\n const resolvedOwner = await getService('user').findOne(ownerId);\n if (resolvedOwner === null || resolvedOwner === undefined) {\n throw new ValidationError('Token owner no longer exists');\n }\n tokenOwnerUser = resolvedOwner;\n clampedAdminPermissions = await enforceAdminPermissionsCeiling(\n tokenOwnerUser,\n incomingAdminPermissions\n );\n }\n\n const incomingAdminUserOwner = raw.adminUserOwner;\n if (incomingAdminUserOwner !== undefined) {\n // Owner is immutable; the provided value must match the existing one\n const existingOwner = originalToken.adminUserOwner;\n const existingOwnerId =\n existingOwner === null || existingOwner === undefined\n ? null\n : String(typeof existingOwner === 'object' ? existingOwner.id : existingOwner);\n const requestedOwnerId =\n incomingAdminUserOwner === null ? null : String(incomingAdminUserOwner);\n\n if (requestedOwnerId !== existingOwnerId) {\n throw new ValidationError('adminUserOwner cannot be changed on update');\n }\n }\n }\n\n const baseData = pick(UPDATABLE_FIELDS, attributes) as Record<string, unknown>;\n\n // Migrate legacy null-kind rows to the explicit value on first write\n if (originalToken.kind === null) {\n baseData.kind = 'content-api';\n }\n\n const updatedToken = await strapi.db.query('admin::api-token').update({\n select: SELECT_FIELDS,\n where: { id },\n data: baseData,\n });\n\n if (originalToken.kind === null || originalToken.kind === 'content-api') {\n const incomingPermissions = raw.permissions as string[] | null | undefined;\n\n // custom tokens need to have their permissions updated as well\n if (\n updatedToken.type === constants.API_TOKEN_TYPE.CUSTOM &&\n incomingPermissions !== undefined\n ) {\n const currentPermissionsResult = await strapi.db\n .query('admin::api-token')\n .load(updatedToken, 'permissions');\n\n const currentPermissions = map('action', currentPermissionsResult || []);\n const newPermissions = uniq(incomingPermissions || []);\n\n const actionsToDelete = difference(currentPermissions, newPermissions);\n const actionsToAdd = difference(newPermissions, currentPermissions);\n\n // TODO: improve efficiency here\n await Promise.all(\n actionsToDelete.map((action) =>\n strapi.db.query('admin::api-token-permission').delete({\n where: { action, token: id },\n })\n )\n );\n\n // TODO: improve efficiency here\n await Promise.all(\n actionsToAdd.map((action) =>\n strapi.db.query('admin::api-token-permission').create({\n data: { action, token: id },\n })\n )\n );\n }\n // if type is not custom, make sure any old permissions get removed\n else if (updatedToken.type !== constants.API_TOKEN_TYPE.CUSTOM) {\n await strapi.db.query('admin::api-token-permission').delete({\n where: { token: id },\n });\n }\n\n const permissionsFromDb = await strapi.db\n .query('admin::api-token')\n .load(updatedToken, 'permissions');\n\n return {\n ...updatedToken,\n permissions: permissionsFromDb ? permissionsFromDb.map((p: any) => p.action) : undefined,\n } as AnyApiToken;\n }\n\n // kind === 'admin'\n if (clampedAdminPermissions !== undefined) {\n if (tokenOwnerUser === undefined) {\n throw new ValidationError('Updating admin permissions requires a resolved token owner');\n }\n await assignAdminPermissionsToToken(id, clampedAdminPermissions, tokenOwnerUser);\n }\n\n const adminPermissionsFromDb = await strapi.db\n .query('admin::api-token')\n .load(updatedToken, 'adminPermissions');\n\n const adminUserOwnerFromDb = await strapi.db\n .query('admin::api-token')\n .load(updatedToken, 'adminUserOwner');\n\n return {\n ...updatedToken,\n adminPermissions: adminPermissionsFromDb || [],\n adminUserOwner: toAdminTokenOwner(adminUserOwnerFromDb),\n } as AnyApiToken;\n};\n\nconst count = async (where = {}): Promise<number> => {\n return strapi.db.query('admin::api-token').count({ where });\n};\n\n/**\n * Delete all admin API tokens owned by the given user, including their associated admin permissions.\n * Called when the owner user is deleted so tokens don't linger with a dangling owner FK.\n */\nconst deleteAdminTokensForUser = async (userId: Data.ID): Promise<void> => {\n const tokens = await strapi.db.query('admin::api-token').findMany({\n where: { kind: 'admin', adminUserOwner: { id: userId } },\n select: ['id'],\n populate: ['adminPermissions'],\n });\n\n for (const token of tokens) {\n const permissionIds = ((token.adminPermissions as Array<{ id: Data.ID }>) ?? [])\n .map((p) => p.id)\n .filter((id) => id !== null && id !== undefined);\n\n if (permissionIds.length > 0) {\n await getService('permission').deleteByIds(permissionIds);\n }\n\n await strapi.db.query('admin::api-token').delete({ where: { id: token.id } });\n }\n};\n\n// -------------------------------------------------------------------------\n// Service interfaces\n// -------------------------------------------------------------------------\n\ninterface SharedTokenMethods {\n hash(accessKey: string): string;\n checkSaltIsDefined(): void;\n /** Kind-agnostic lookup by hashed access key — used by the auth strategy. */\n getByAccessKey(accessKeyHash: string, options?: GetByOptions): Promise<AnyApiToken | null>;\n /** Total count across all kinds. */\n countAll(where?: object): Promise<number>;\n reconcileTokenPermissionsToUserCeiling(\n userPermissions: Permission[],\n tokenPermissions: Permission[]\n ): { toDelete: Permission[]; toUpdate: { id: Data.ID; conditions: string[] }[] };\n}\n\nexport interface ContentApiTokenService extends SharedTokenMethods {\n create(attributes: ContentApiApiTokenBody, callingUser?: AdminUser): Promise<ContentApiApiToken>;\n list(callingUser: AdminUser): Promise<ContentApiApiToken[]>;\n getById(id: string | number, options?: GetByOptions): Promise<ContentApiApiToken | null>;\n getByName(name: string, options?: GetByOptions): Promise<ContentApiApiToken | null>;\n update(\n id: string | number,\n attributes: Partial<ContentApiApiTokenBody>\n ): Promise<ContentApiApiToken>;\n revoke(id: string | number): Promise<ContentApiApiToken>;\n regenerate(id: string | number): Promise<ContentApiApiToken>;\n exists(where: WhereParams): Promise<boolean>;\n count(where?: object): Promise<number>;\n}\n\nexport interface AdminTokenService extends SharedTokenMethods {\n authenticateAdminToken(accessToken: string): Promise<AdminTokenAuthenticationResult>;\n create(attributes: AdminTokenBody, callingUser: AdminUser): Promise<AdminApiToken>;\n list(callingUser: AdminUser): Promise<AdminApiToken[]>;\n getById(id: string | number, options?: GetByOptions): Promise<AdminApiToken | null>;\n getByName(name: string, options?: GetByOptions): Promise<AdminApiToken | null>;\n update(id: string | number, attributes: Partial<AdminTokenBody>): Promise<AdminApiToken>;\n revoke(id: string | number): Promise<AdminApiToken>;\n regenerate(id: string | number): Promise<AdminApiToken>;\n exists(where: WhereParams): Promise<boolean>;\n count(where?: object): Promise<number>;\n assignAdminPermissionsToToken(\n tokenId: Data.ID,\n permissions: PermissionInput[],\n ceilingUser: AdminUser\n ): Promise<Permission[]>;\n syncPermissionsForUser(userId: Data.ID): Promise<void>;\n syncPermissionsForRole(roleId: Data.ID): Promise<void>;\n deleteTokensForUser(userId: Data.ID): Promise<void>;\n}\n\n// -------------------------------------------------------------------------\n// Factory\n// -------------------------------------------------------------------------\n\nfunction createTokenService(kind: 'content-api'): ContentApiTokenService;\nfunction createTokenService(kind: 'admin'): AdminTokenService;\nfunction createTokenService(\n kind: 'content-api' | 'admin'\n): ContentApiTokenService | AdminTokenService {\n const shared: SharedTokenMethods = {\n hash,\n checkSaltIsDefined,\n getByAccessKey: (accessKeyHash, options) => getBy({ accessKey: accessKeyHash }, options),\n countAll: count,\n reconcileTokenPermissionsToUserCeiling,\n };\n\n if (kind === 'content-api') {\n const svc: ContentApiTokenService = {\n ...shared,\n create: (attributes: ContentApiApiTokenBody, callingUser?: AdminUser) =>\n create({ ...attributes, kind: 'content-api' }, callingUser) as Promise<ContentApiApiToken>,\n list: (callingUser: AdminUser) =>\n list(callingUser, { filter: { kind: 'content-api' } }) as Promise<ContentApiApiToken[]>,\n getById: (id: string | number, options?: GetByOptions) =>\n getBy(\n {\n $and: [{ id }, { $or: [{ kind: 'content-api' }, { kind: { $null: true } }] }],\n } as any,\n options\n ) as Promise<ContentApiApiToken | null>,\n getByName: (name: string, options?: GetByOptions) =>\n getBy(\n {\n $and: [{ name }, { $or: [{ kind: 'content-api' }, { kind: { $null: true } }] }],\n } as any,\n options\n ) as Promise<ContentApiApiToken | null>,\n update: (id: string | number, attributes: Partial<ContentApiApiTokenBody>) =>\n update(id, attributes) as Promise<ContentApiApiToken>,\n revoke: (id: string | number) => revoke(id) as Promise<ContentApiApiToken>,\n regenerate: (id: string | number) => regenerate(id) as Promise<ContentApiApiToken>,\n exists,\n count,\n };\n return svc;\n }\n\n const svc: AdminTokenService = {\n ...shared,\n authenticateAdminToken,\n create: (attributes: AdminTokenBody, callingUser: AdminUser) =>\n create({ ...attributes, kind: 'admin' }, callingUser) as Promise<AdminApiToken>,\n list: (callingUser: AdminUser) =>\n list(callingUser, { filter: { kind: 'admin' } }) as Promise<AdminApiToken[]>,\n getById: (id: string | number, options?: GetByOptions) =>\n getBy({ id, kind: 'admin' }, options) as Promise<AdminApiToken | null>,\n getByName: (name: string, options?: GetByOptions) =>\n getBy({ name, kind: 'admin' }, options) as Promise<AdminApiToken | null>,\n update: (id: string | number, attributes: Partial<AdminTokenBody>) =>\n update(id, attributes) as Promise<AdminApiToken>,\n revoke: (id: string | number) => revoke(id) as Promise<AdminApiToken>,\n regenerate: (id: string | number) => regenerate(id) as Promise<AdminApiToken>,\n exists,\n count,\n assignAdminPermissionsToToken,\n syncPermissionsForUser: syncApiTokenPermissionsForUser,\n syncPermissionsForRole: syncApiTokenPermissionsForRole,\n deleteTokensForUser: deleteAdminTokensForUser,\n };\n return svc;\n}\n\nexport type { GetByOptions };\n\nexport {\n createTokenService,\n create,\n count,\n regenerate,\n exists,\n checkSaltIsDefined,\n hash,\n list,\n revoke,\n getById,\n update,\n getByName,\n getBy,\n authenticateAdminToken,\n assignAdminPermissionsToToken,\n enforceAdminPermissionsCeiling,\n reconcileTokenPermissionsToUserCeiling,\n syncApiTokenPermissionsForUser,\n syncApiTokenPermissionsForRole,\n deleteAdminTokensForUser,\n};\n"],"names":["SUPER_ADMIN_CODE","constants","ValidationError","NotFoundError","UnauthorizedError","errors","assertOwnerMatchesCallingUser","adminUserOwner","callingUser","undefined","ownerId","String","callingUserId","id","existingUser","strapi","db","query","findOne","select","where","isSuperAdmin","user","roles","some","r","code","getOwnerId","token","owner","resolveAdminTokenOwnerId","toAdminTokenOwner","Error","firstname","lastname","username","email","SELECT_FIELDS","POPULATE_FIELDS","UPDATABLE_FIELDS","assertCustomTokenPermissionsValidity","type","permissions","API_TOKEN_TYPE","CUSTOM","isEmpty","isArray","validPermissions","contentAPI","providers","action","keys","invalidPermissions","difference","join","isValidLifespan","lifespan","isNil","isNumber","Object","values","API_TOKEN_LIFESPANS","includes","assertValidLifespan","assertLegacyKindFields","attributes","raw","adminPermissions","assertAdminKindFields","assertAdminPermissionsValidity","length","validActions","getService","actionProvider","perm","validatePermissionsExist","enforceAdminPermissionsCeiling","requestedPermissions","conditionProvider","sanitize","permissionDomain","sanitizeConditions","map","sanitized","actionParameters","conditions","userPermissions","findUserPermissions","exceeding","clamped","requested","requestedSubject","subject","matchingUserPerms","filter","userPerm","userSubject","label","push","anyUserPermHasAllFields","p","properties","fields","requestedFields","effectiveUserFields","uniq","flatMap","exceedingFields","f","anyUserPermIsUnconditional","enforcedConditions","createApiTokenAdminPermissions","tokenId","permissionsWithToken","permAsPermission","create","apiToken","role","createdPermissions","createMany","COMPARABLE_FIELDS","pickComparableFields","pick","jsonClean","data","JSON","parse","stringify","arePermissionsEqual","p1","p2","isEqual","assignAdminPermissionsToToken","ceilingUser","clampedPermissions","existingPermissions","findMany","permissionsToAdd","differenceWith","permissionsToDelete","deleteByIds","prop","allCurrentPermissions","reconcileTokenPermissionsToUserCeiling","tokenPermissions","toDelete","toUpdate","forEach","tokenPerm","tokenSubject","tokenFields","fieldCeilingExceeded","currentConditions","conditionsChanged","c","syncApiTokenPermissionsForUser","userId","populate","userEffectivePermissions","tokens","kind","tokensWithPermissions","Array","update","syncApiTokenPermissionsForRole","roleId","users","Promise","allSettled","flattenTokenPermissions","getBy","whereParams","options","includeDecryptedKey","selectFields","computedKind","result","omit","assign","encryptedKey","accessKey","decrypt","exists","hash","apiTokenCfg","config","get","salt","crypto","createHmac","digest","authenticateAdminToken","accessToken","authenticated","expiryError","checkExpiry","error","isActive","blocked","updateLastUsedAt","ability","engine","generateTokenAbility","credentials","getExpirationFields","isValidNumber","Number","isFinite","expiresAt","Date","now","encryptionService","randomBytes","toString","encrypt","castedContentApiApiTokenBody","all","currentPermissions","load","castedAdminTokenBody","clampedAdminPermissions","currentAdminPermissions","regenerate","checkSaltIsDefined","process","env","API_TOKEN_SALT","emitWarning","set","list","ownershipWhere","$or","kindWhere","$null","orderBy","name","revoke","permissionIds","permId","deletedToken","delete","originalToken","effectiveStoredKind","tokenOwnerUser","incomingType","incomingPermissions","resolvedType","changingTypeToCustom","incomingAdminPermissions","resolvedOwner","incomingAdminUserOwner","existingOwner","existingOwnerId","requestedOwnerId","baseData","updatedToken","currentPermissionsResult","newPermissions","actionsToDelete","actionsToAdd","permissionsFromDb","adminPermissionsFromDb","adminUserOwnerFromDb","count","deleteAdminTokensForUser","createTokenService","shared","getByAccessKey","accessKeyHash","countAll","svc","getById","$and","getByName","syncPermissionsForUser","syncPermissionsForRole","deleteTokensForUser"],"mappings":"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"}
@@ -5,9 +5,10 @@ import constants from './constants.mjs';
5
5
  import { getService } from '../utils/index.mjs';
6
6
  import permissionDomain from '../domain/permission/index.mjs';
7
7
  import { validatePermissionsExist } from '../validation/permission.mjs';
8
+ import { checkExpiry, updateLastUsedAt } from '../strategies/api-token-utils.mjs';
8
9
 
9
10
  const { SUPER_ADMIN_CODE } = constants;
10
- const { ValidationError, NotFoundError } = errors;
11
+ const { ValidationError, NotFoundError, UnauthorizedError } = errors;
11
12
  const assertOwnerMatchesCallingUser = async (adminUserOwner, callingUser)=>{
12
13
  if (callingUser === undefined || callingUser === null) {
13
14
  throw new ValidationError('adminUserOwner requires an authenticated admin user');
@@ -34,6 +35,16 @@ const getOwnerId = (token)=>{
34
35
  const owner = token.adminUserOwner;
35
36
  return String(typeof owner === 'object' ? owner.id : owner);
36
37
  };
38
+ const resolveAdminTokenOwnerId = (token)=>{
39
+ const owner = token.adminUserOwner;
40
+ if (owner === null || owner === undefined) {
41
+ return null;
42
+ }
43
+ if (typeof owner === 'object') {
44
+ return owner.id;
45
+ }
46
+ return owner;
47
+ };
37
48
  const toAdminTokenOwner = (owner)=>{
38
49
  if (owner === null || owner === undefined) {
39
50
  throw new Error('adminUserOwner is required');
@@ -502,6 +513,63 @@ const pickComparableFields = pick(COMPARABLE_FIELDS);
502
513
  const salt = apiTokenCfg.salt;
503
514
  return crypto.createHmac('sha512', salt).update(accessKey).digest('hex');
504
515
  };
516
+ const authenticateAdminToken = async (accessToken)=>{
517
+ const apiToken = await getBy({
518
+ accessKey: hash(accessToken)
519
+ });
520
+ if (apiToken === null || apiToken === undefined) {
521
+ return {
522
+ authenticated: false
523
+ };
524
+ }
525
+ if (apiToken.kind !== 'admin') {
526
+ return {
527
+ authenticated: false
528
+ };
529
+ }
530
+ const expiryError = checkExpiry(apiToken);
531
+ if (expiryError !== null) {
532
+ return {
533
+ authenticated: false,
534
+ error: expiryError
535
+ };
536
+ }
537
+ const ownerId = resolveAdminTokenOwnerId(apiToken);
538
+ if (ownerId === null) {
539
+ return {
540
+ authenticated: false,
541
+ error: new UnauthorizedError('Token owner not found')
542
+ };
543
+ }
544
+ const user = await strapi.db.query('admin::user').findOne({
545
+ where: {
546
+ id: ownerId
547
+ },
548
+ populate: [
549
+ 'roles'
550
+ ]
551
+ });
552
+ if (user === null || user === undefined) {
553
+ return {
554
+ authenticated: false,
555
+ error: new UnauthorizedError('Token owner not found')
556
+ };
557
+ }
558
+ if (user.isActive !== true || user.blocked === true) {
559
+ return {
560
+ authenticated: false,
561
+ error: new UnauthorizedError('Token owner is deactivated')
562
+ };
563
+ }
564
+ await updateLastUsedAt(apiToken);
565
+ const ability = await getService('permission').engine.generateTokenAbility(apiToken.adminPermissions ?? [], user);
566
+ return {
567
+ authenticated: true,
568
+ credentials: apiToken,
569
+ user,
570
+ ability
571
+ };
572
+ };
505
573
  const getExpirationFields = (lifespan)=>{
506
574
  // it must be nil or a finite number >= 0
507
575
  const isValidNumber = isNumber(lifespan) && Number.isFinite(lifespan) && lifespan > 0;
@@ -1002,6 +1070,7 @@ function createTokenService(kind) {
1002
1070
  }
1003
1071
  const svc = {
1004
1072
  ...shared,
1073
+ authenticateAdminToken,
1005
1074
  create: (attributes, callingUser)=>create({
1006
1075
  ...attributes,
1007
1076
  kind: 'admin'
@@ -1032,5 +1101,5 @@ function createTokenService(kind) {
1032
1101
  return svc;
1033
1102
  }
1034
1103
 
1035
- export { assignAdminPermissionsToToken, checkSaltIsDefined, count, create, createTokenService, deleteAdminTokensForUser, enforceAdminPermissionsCeiling, exists, getBy, hash, list, reconcileTokenPermissionsToUserCeiling, regenerate, revoke, syncApiTokenPermissionsForRole, syncApiTokenPermissionsForUser, update };
1104
+ export { assignAdminPermissionsToToken, authenticateAdminToken, checkSaltIsDefined, count, create, createTokenService, deleteAdminTokensForUser, enforceAdminPermissionsCeiling, exists, getBy, hash, list, reconcileTokenPermissionsToUserCeiling, regenerate, revoke, syncApiTokenPermissionsForRole, syncApiTokenPermissionsForUser, update };
1036
1105
  //# sourceMappingURL=api-token.mjs.map