payload icon indicating copy to clipboard operation
payload copied to clipboard

"disableLocalStrategy: true" still asking for email or nickname

Open antonbrams opened this issue 1 year ago • 6 comments

Environment Info

    "next": "15.0.0-canary.104",
    "payload": "beta",
    "nodejs": v18.20.4

Describe the Bug

I want to create a custom auth for trainees that can login with their firstname, lastname and trainee_id. There is no need for password, email or nicknames. I've find out that disableLocalStrategy set to true is ignored and still requires email/nickname and password. If i'm doing something wrong, please tell me how to fix it?

Reproduction Steps

import type {CollectionConfig} from 'payload'

export default {
	slug: 'trainees',
	labels: {
		singular: 'Azubi',
		plural: 'Azubis',
	},
	auth: {
		disableLocalStrategy: true,
		strategies: [
			{
				identityField: 'trainee_id',
				name: 'custom-strategy',
				async authenticate({headers, payload}) {
					const {docs} = await payload.find({
						collection: 'trainees',
						where: {
							name_first: {equals: headers.get('name_first')},
							name_last: {equals: headers.get('name_last')},
							trainee_id: {equals: headers.get('trainee_id')},
						},
					})
					return {user: docs[0]}
				},
			},
		],
	},
	fields: [
		{
			name: 'name_first',
			label: 'Vorname',
			type: 'text',
			required: true,
		},
		{
			name: 'name_last',
			label: 'Nachname',
			type: 'text',
			required: true,
		},
		{
			name: 'trainee_id',
			label: 'Matrikelnummer',
			type: 'text',
			required: true,
		},
	],
} as const satisfies CollectionConfig

is called by

	const result = await payload.login({
		collection: 'trainees',
		data: {
			name_first: 'Hassan',
			name_last: 'Altay',
			trainee_id: '43523452345',
		},
	})
	console.log(result)

causes

dock-payload   |  ⨯ node_modules/payload/dist/auth/operations/login.js (56:1) @ loginOperation
dock-payload   |  ⨯ ValidationError: The following field is invalid: email
dock-payload   |     at async $$ACTION_0 (./src/app/logic/actions.ts:52:20)
dock-payload   | digest: "1954918542"
dock-payload   | Cause: {
dock-payload   |   collection: 'trainees',
dock-payload   |   errors: [ { field: 'email', message: 'This field is required.' } ]
dock-payload   | }
dock-payload   |   54 |         // cannot login with username, did not provide email
dock-payload   |   55 |         if (!canLoginWithUsername && !sanitizedEmail) {
dock-payload   | > 56 |             throw new ValidationError({
dock-payload   |      | ^
dock-payload   |   57 |                 collection: collectionConfig.slug,
dock-payload   |   58 |                 errors: [
dock-payload   |   59 |                     {

antonbrams avatar Sep 05 '24 14:09 antonbrams

can somebody help me with this, please? :)

antonbrams avatar Sep 10 '24 14:09 antonbrams

hi , you are reading headers in custom strategies ?!!

geminigeek avatar Sep 12 '24 12:09 geminigeek

hi , you are reading headers in custom strategies ?!!

yes, i can pass my own headers as you see

name_first: {equals: headers.get('name_first')},
name_last: {equals: headers.get('name_last')},
trainee_id: {equals: headers.get('trainee_id')},

but this parameter disableLocalStrategy: true doesn't have any effect, the payload still requires email/nickname and password field

antonbrams avatar Sep 12 '24 20:09 antonbrams

hi,

i didn't see that your setting headers, it seems strategy are an array so they are fired one after another till any of them fulfills the record , i am build a custom strategy, looking forward to a solution too

geminigeek avatar Sep 12 '24 22:09 geminigeek

I think the custom strategies is not supposed to use with login auth operation. It's for accessing the API directly without doing the login auth operation. I ended up just creating custom login root endpoint based on the source here https://github.com/payloadcms/payload/blob/v2.28.0/packages/payload/src/auth/operations/login.ts#L43

import { CookieOptions, Response } from 'express'
import jwt from 'jsonwebtoken'
import { PayloadRequest } from 'payload/types'

const getCookieExpiration = (seconds = 7200) => {
  const currentTime = new Date()
  currentTime.setSeconds(currentTime.getSeconds() + seconds)
  return currentTime
}

export async function handleCustomLogin(req: PayloadRequest, res: Response) {
  const { payload, body: credentials } = req
 
  const user = ... // get user here
  
  if (!user) return res.status(401).send('User not found')

  const { config, secret } = payload
  const collectionConfig = payload.collections['users'].config

  const fieldsToSign = {
    id: user.id,
    collection: 'users',
    email: user.email,
  }
  const token = jwt.sign(fieldsToSign, secret, {
    expiresIn: collectionConfig.auth.tokenExpiration,
  })

  const cookieOptions: CookieOptions = {
    domain: undefined,
    expires: getCookieExpiration(collectionConfig.auth.tokenExpiration),
    httpOnly: true,
    path: '/',
    sameSite: collectionConfig.auth.cookies.sameSite,
    secure: collectionConfig.auth.cookies.secure,
  }

  if (collectionConfig.auth.cookies.domain) cookieOptions.domain = collectionConfig.auth.cookies.domain

  res.cookie(`${config.cookiePrefix}-token`, token, cookieOptions)

  const result = {
    exp: (jwt.decode(token) as jwt.JwtPayload).exp,
    token,
    user,
  }
  return res.json(result)
}

Please be aware that I strip a lot of function from the upstream source, so it might cause some unintended effect

ffd114 avatar Sep 24 '24 10:09 ffd114

This issue has been marked as stale due to lack of activity.

To keep this issue open, please indicate that it is still relevant in a comment below.

github-actions[bot] avatar Dec 13 '24 05:12 github-actions[bot]

as @ffd114 said, the local operation payload.login is not meant to be used with disableLocalStrategy: true. It will throw an error here: https://github.com/payloadcms/payload/blob/main/packages/payload/src/auth/operations/login.ts#L71-L73

JarrodMFlesch avatar Jul 14 '25 13:07 JarrodMFlesch

This issue has been automatically locked. Please open a new issue if this issue persists with any additional detail.

github-actions[bot] avatar Jul 22 '25 05:07 github-actions[bot]