Hi,
I'm new to payload and I'm a bit unsure how to add auth based hooks to the collection. I have created the actual hook, but how do I link it with the collection? Other types of hook are added under "hooks" in the collection, but there is no "AfterLogin" type I can use. How exactly do I tie a CollectionAfterLoginHook to the document?
Thanks!
@shisue You should be able to add
afterLogin
and other Auth-enabled hooks the same way you would add in the other hooks.
/**
* Hooks to modify Payload functionality
*/
hooks?: {
beforeOperation?: BeforeOperationHook[];
beforeValidate?: BeforeValidateHook[];
beforeChange?: BeforeChangeHook[];
afterChange?: AfterChangeHook[];
beforeRead?: BeforeReadHook[];
afterRead?: AfterReadHook[];
beforeDelete?: BeforeDeleteHook[];
afterDelete?: AfterDeleteHook[];
afterError?: AfterErrorHook;
beforeLogin?: BeforeLoginHook[];
afterLogin?: AfterLoginHook[];
afterLogout?: AfterLogoutHook[];
afterMe?: AfterMeHook[];
afterRefresh?: AfterRefreshHook[];
afterForgotPassword?: AfterForgotPasswordHook[];
};
Could you share your collection config and hook code here? I can try to help you out
Thanks! This actually solved my issue, I was doing logic field-based but had to be collection-based everywhere.
Awesome, let me know if you run into anything else!
I'm running into a small other issue. I'm trying to create the Last Active field, and upon trying to deconstruct user I keep getting a type error:
import type { User } from 'payload/generated-types'
import type { CollectionAfterLoginHook } from 'payload/types'
// ensure there is always a
user
role
// do not let non-admins change roles
export const lastLoggedIn: CollectionAfterLoginHook<User & { id: string }> = async ({ req, user, token }) => {
return [...user, { lastLoggedIn: new Date() }];
}
My Last Active field under users looks like this:
{
name: 'lastActive',
label: 'Last Active',
type: 'date',
access: {
read: () => true,
update: () => true,
create: () => false,
},
saveToJWT: true,
},
A couple things:
- the Login operation isn't modifying a document, so you wouldn't return an updated
user
object here. (also, if you were, return an object instead of an array. That's likely the type error)
- you can use the Local API to make an update to the document, here's a snippet of how that could work:
hooks: {
afterLogin: [
async ({ user }) => {
await payload.update({
collection: 'users',
id: user.id,
data: {
lastActive: new Date(),
},
});
}
],
},
Thanks!
A followup question, is there a way to make fields required depending on a given role a user has without using hooks, or is hooks the way to go when enforcing this type of behavior?
Sure, you can create your own validation functions at the field level. Check out this example that makes a field required if the user has an
admin
role:
{
name: 'validation',
type: 'text',
label: 'validation',
validate: (value, { user }) => {
if (user.role === 'admin') {
return value ? true : 'Please provide a value'
}
return true;
},
},
I pass the
validate
property the
value
of the field, as well as the
user
object. If the user's role is
admin
it checks the value, and returns true if it exists, otherwise it returns 'Please provide a value' as an error statement.
If a user's role is not
admin
, it does not require a value and returns true.
The
validate
property can either return
true
or a string to use as the error that is returned if the validation is not passed.
Thanks!
Star
Discord
online
Get help straight from the Payload team with an Enterprise License.