In what cases can `session.user` be undefined?
Unanswered
GetPsyched posted this in #help-forum
I've thought about this a ton but never really understood it
39 Replies
Of course, given that
session is definedKomondor
It depends on what auth provider you're using. You would need to set session.user in order for session.user to be defined
@Komondor It depends on what auth provider you're using. You would need to set session.user in order for session.user to be defined
So, say I'm defining a custom callback for
session in the auth config, I can be sure to always have session.user?Komondor
If you're setting it in that callback then yes
Awesome
Komondor
I'm assuming you're using NextAuth?
Yup
I can override user to be any type I want?
Komondor
Yep that callback will provide the session and the user. If using jwt then it will provide the jwt token instead of user. From either of those, you can set a user field in the session object
Also, is this a good way to set a user by fetching from a database? https://nextjs-forum.com/post/1213243382579863552#message-1213243382579863552
Komondor
This thread has examples
https://nextjs-forum.com/post/1230876557019578450
https://nextjs-forum.com/post/1230876557019578450
@GetPsyched Also, is this a good way to set a user by fetching from a database? https://discord.com/channels/752553802359505017/1213243382579863552/1213243382579863552
I currently do the fetching inside my custom
session callback and not using an adapter like this person did.Unsure which practice is better since I didn't find any docs on it
Komondor
Fetching user from DB when inside callback is fine
If you're not using a db adapter then you won't have the user provided to you in that callback
Which is fine. It depends on your usecase
@Komondor If you're not using a db adapter then you won't have the user provided to you in that callback
Sorry but I didn't understand this. I'm getting the user from my current implementation:
export const authOptions: NextAuthOptions = {
callbacks: {
async session({ session }) {
session.person = (await db.query.persons.findFirst({
where: ({ email }, { eq }) => eq(email, session.user.email),
}))!;
return session;
},
...
},
...
};declare module 'next-auth' {
// A nicer way to assert that `email` will not be
// undefined since we only use the Google provider as of now.
interface User extends DefaultUser {
email: string;
}
interface Session extends DefaultSession {
person: InferSelectModel<typeof persons>;
user: User;
}
}Moreover, should I do this?
instead of this?
declare module 'next-auth' {
interface Session extends DefaultSession {
user: InferSelectModel<typeof persons>;
}
}instead of this?
declare module 'next-auth' {
interface Session extends DefaultSession {
person: InferSelectModel<typeof persons>;
user: User;
}
}Unsure if this might break things or not.
Komondor
I would limit the fields in your person object / user object in the session to just a few. I wouldn't stick the whole db object in there
@Komondor I would limit the fields in your person object / user object in the session to just a few. I wouldn't stick the whole db object in there
My person table has just 5-6 fields anyway.
@GetPsyched Moreover, should I do this?
tsx
declare module 'next-auth' {
interface Session extends DefaultSession {
user: InferSelectModel<typeof persons>;
}
}
instead of this?
tsx
declare module 'next-auth' {
interface Session extends DefaultSession {
person: InferSelectModel<typeof persons>;
user: User;
}
}
I'm assuming that's a yes to the former given it's just a few fields?
Also, I though it would be good to cache this fetch since it'll be done each time the callback is called?
ref: https://github.com/nitkkr-dev/nitkkr/pull/147/commits/c4951df66f88c4615d71751f4f75aadc06417468
ref: https://github.com/nitkkr-dev/nitkkr/pull/147/commits/c4951df66f88c4615d71751f4f75aadc06417468
@GetPsyched My person table has just 5-6 fields anyway.
Komondor
Right but in the future when you add more fields to the User model, you may forget that you're putting the entire user model in the session here. So I would specifically map just the few fields you need in the session, instead of putting the entire User model in there
Fair enough!
@GetPsyched Also, I though it would be good to cache this fetch since it'll be done each time the callback is called?
ref: <https://github.com/nitkkr-dev/nitkkr/pull/147/commits/c4951df66f88c4615d71751f4f75aadc06417468>
Komondor
Meh I wouldn't worry about caching it if you have an index on email. I'd only worry about caching complex queries. How long does it stay cached until it expires?
Oof, seems like caching is still experimental in react
@Komondor Meh I wouldn't worry about caching it if you have an index on email. I'd only worry about caching complex queries. How long does it stay cached until it expires?
I think it's indefinite? I didn't see anything written about expiry in [the docs](https://react.dev/reference/react/cache)
@GetPsyched I think it's indefinite? I didn't see anything written about expiry in [the docs](<https://react.dev/reference/react/cache>)
Komondor
I'd always try to have a TTL on cached items
and you'll have to remember to expire the cache if you ever support users changing emails
Yeah, although due to the nature of my app, changing emails will never be a thing
@GetPsyched I'm assuming that's a yes to the former given it's just a few fields?
Bumping since I wanted a confirmation on this
@GetPsyched Bumping since I wanted a confirmation on this
Komondor
by all means let other people chime in for confirmation. Could you clarify exaclty what you are looking for confirmation on?
@GetPsyched Moreover, should I do this?
tsx
declare module 'next-auth' {
interface Session extends DefaultSession {
user: InferSelectModel<typeof persons>;
}
}
instead of this?
tsx
declare module 'next-auth' {
interface Session extends DefaultSession {
person: InferSelectModel<typeof persons>;
user: User;
}
}
WRT these bits of code, I wanted to ask whether it is safe to override the
session.user type altogether since that's auto-populated depending on the provider that is used. For context, I'm using the Google provider and plan to implement a generic email providerMight be worth noting that the 4 fields I'm getting in the existing
User type, id, name, email, image are included in my custom type already.@GetPsyched Might be worth noting that the 4 fields I'm getting in the existing `User` type, `id`, `name`, `email`, `image` are included in my custom type already.
Komondor
IMO I would not override the object but instead I would decorate the object
but of course, feel free to wait for other opinions
@Komondor IMO I would not override the object but instead I would decorate the object
Yeah, that's my current approach