Skip to content

Custom Authentication and Authorization with no persisted user #13105

Open
@Jack-Gitter

Description

@Jack-Gitter

Describe the Bug.

Hi all, I'm starting to use Payload now and have a question about the authentication process. The CMS will be part of an SSO system, where users authenticate via Okta. Okta returns a JWT, which is then used to access all the individual applications. I want Payload to be the same. I understand that to access the admin panel, your collection must have authentication enabled. As such, I've implemented a custom auth strategy which simply parses the JWT, and returns a user object without persisting anything to the database.

export const Users: CollectionConfig = {
  slug: 'users',
  timestamps: false,
  admin: {
    useAsTitle: 'email',
  },
  access: {
    admin: ({ req }: { req: PayloadRequest }) => {
      return isAdmin(req) || hasRole([RoleType.admin, RoleType.editor], req)
    },
  },
  auth: {
    disableLocalStrategy: true,
    strategies: [
      {
        name: 'JWT',
        authenticate: authenticate,
      },
    ],
  },
  fields: [
    {
      name: 'name',
      type: 'text',
    },
    {
      name: 'isAdmin',
      type: 'checkbox',
    },
    {
      name: 'id',
      type: 'text',
    },
  ],
}

Here is my authenticate function

export async function authenticate({ headers, payload }: { headers: Headers; payload: Payload }) {
  const cookies = headers.get('cookie')
  if (!cookies) {
    return {
      user: null,
    }
  }
  const parsedCookie = cookie.parse(cookies)
  const jwt = parsedCookie.JWT
  if (!jwt) {
    return {
      user: null,
    }
  }
  const res = verifyJWT(jwt)
  if (!res) {
    return {
      user: null,
    }
  }
  const user = {
    id: res.email,
    name: res.name,
    isAdmin: res.isAdmin,
    collection: 'users',
  }
  return {
    user: user,
  } satisfies AuthStrategyResult
}

Now this works to access the admin panel, but when I want to actually view a collection (like the users collection), I get the following error:

[error: insert or update on table "payload_preferences_rels" violates foreign key constraint "payload_preferences_rels_users_fk"] {
  length: 339,
  severity: 'ERROR',
  code: '23503',
  detail: 'Key (users_id)=(redacted@gmail.com) is not present in table "users".',
  hint: undefined,
  position: undefined,
  internalPosition: undefined,
  internalQuery: undefined,
  where: undefined,
  schema: 'public',
  table: 'payload_preferences_rels',
  column: undefined,
  dataType: undefined,
  constraint: 'payload_preferences_rels_users_fk',
  file: 'ri_triggers.c',
  line: '2610',
  routine: 'ri_ReportViolation'
}

It seems like when I'm attempting to access the users (or any other collection) payload first looks up the user based on the primary key that I've returned from my authenticate function. Why does it do this, and can I bypass it? I couldn't find this behavior documented anywhere

Reproduction Steps

  • Create the collections and authentication function as listed above
  • Attempt to view the users collection in the admin panel

Environment Info

Binaries:
  Node: 23.10.0
  npm: 10.9.2
  Yarn: N/A
  pnpm: 10.5.2
Relevant Packages:
  payload: 3.46.0
Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 24.4.0: Fri Apr 11 18:34:14 PDT 2025; root:xnu-11417.101.15~117/RELEASE_ARM64_T8122
  Available memory (MB): 24576
  Available CPU cores: 8

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: uiRelated to the admin panel.status: needs-triagePossible bug which hasn't been reproduced yet

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions