{"record":{"id":"86ed763ba78c4e23","repo":"toeverything/AFFiNE","slug":"action-forbidden-86ed76","errorCode":"action_forbidden","errorMessage":"You are not allowed to perform this action.","messagePattern":"You are not allowed to perform this action\\.","errorType":"exception","errorClass":"ActionForbidden","httpStatus":403,"severity":"error","filePath":"packages/backend/server/src/core/auth/resolver.ts","lineNumber":89,"sourceCode":"  @Query(() => UserType, {\n    name: 'currentUser',\n    description: 'Get current user',\n    nullable: true,\n  })\n  currentUser(@CurrentUser() user?: CurrentUser): UserType | undefined {\n    return user;\n  }\n\n  @ResolveField(() => ClientTokenType, {\n    name: 'token',\n    deprecationReason: 'use auth session exchange instead',\n  })\n  async clientToken(\n    @CurrentUser() currentUser: CurrentUser,\n    @Parent() user: UserType\n  ): Promise<ClientTokenType> {\n    if (user.id !== currentUser.id) {\n      throw new ActionForbidden();\n    }\n\n    const userSession = await this.auth.createUserSession(user.id);\n\n    return {\n      sessionToken: userSession.sessionId,\n      token: userSession.sessionId,\n      refresh: '',\n    };\n  }\n\n  @Public()\n  @Mutation(() => Boolean)\n  async changePassword(\n    @Args('token') token: string,\n    @Args('newPassword') newPassword: string,\n    @Args('userId', { type: () => String, nullable: true }) userId?: string\n  ) {","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/backend/server/src/core/auth/resolver.ts#L71-L107","documentation":"The deprecated GraphQL field UserType.token (authResolver.clientToken) mints a legacy client session token and is protected: if the parent user's id differs from the authenticated CurrentUser's id, it throws ActionForbidden (action_forbidden). You can only ever request this field for yourself; its deprecationReason directs clients to the auth session exchange flow instead.","triggerScenarios":"A GraphQL query selecting user { token } where the user argument/id resolved is another user (e.g. via a user lookup by email); admin tooling listing users and naively selecting token on every node; cached queries replayed under a different signed-in user.","commonSituations":"Admin dashboards bulk-querying the field; queries built by stitching fragments that include the deprecated selection; clients still on the pre-exchange auth model after upgrading past the deprecation.","solutions":["Only include token in selections where user.id === current signed-in user id","Migrate to the auth session exchange flow (POST /api/auth/session/exchange with the one-time code) - the field is deprecated","Audit shared GraphQL fragments so the deprecated selection is not silently included for other users","Remove the field from bulk/admin listings entirely"],"exampleFix":"# before\nquery AdminUsers {\n  users { id email token } # token forbidden for every non-self user\n}\n\n# after\nquery AdminUsers {\n  users { id email } # drop the deprecated field\n}\n\n# self token: use the session exchange instead of `token`\n# clientToken -> POST /api/auth/session/exchange { code, installationId, platform }","handlingStrategy":"validation","validationCode":"function buildUserSelection(currentUserId: string, targetUserId: string) {\n  const base = 'id email';\n  // deprecated self-only field: include only when querying yourself\n  return targetUserId === currentUserId ? `${base} token` : base;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Migrate off UserType.token to the auth session exchange endpoint","Lint GraphQL operations for the deprecated selection so it cannot sneak into shared fragments","Never include auth-credential fields in bulk/admin listings"],"tags":["auth","graphql","deprecated-api","authorization"],"backgroundTag":"authorization-forbidden","analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}