Clerk auth + GraphQL resolver + current user

I’m trying to get the current user ID in a GraphQL resolver.

I’ve created a SDL and service for a me field.

The resolver is defined as:

export const me: QueryResolvers['me'] = async (args, { context }) => {
  return { id: context.currentUser.id }
}

context.currentUser is undefined. Any way I can do this? Thanks!

Possible duplicate/related issue for awareness: Redwood v7.0.0 Upgrade Guide - #66 by n1tsua

Hello

To get the current user ID in a RedwoodJS GraphQL resolver, follow these steps:

Create or update the function to extract user details using Clerk.

import { getClerkUser } from ‘src/lib/auth/clerk’

export const getCurrentUser = async (decoded, { token }) => {

if (!decoded) return null

const { id } = await getClerkUser(token)

return { id }

}

Ensure the handler uses this function.

import { createGraphQLHandler } from ‘@redwoodjs/api’

import { getCurrentUser } from ‘src/lib/auth’

export const handler = createGraphQLHandler({

getCurrentUser,

// other options like schema and services

})

Use currentUser in the resolver.

export const me: QueryResolvers[‘me’] = async (_args, { context }) => {

const currentUser = context.currentUser

if (!currentUser) throw new Error(‘User not authenticated’)

return { id: currentUser.id }

This setup ensures currentUser is available in your resolver​ (RedwoodJS Community

Hope it helps !

Thank you
grayson

Hi @willmruzek as @Grayson noted, the request needs to be authenticated such that the context is populated.

in your me GraphQL query operation did you set @requrieAuth and that auth provider are you using?

If in

export const me: QueryResolvers['me'] = async (args, { context }) => {
  return { id: context.currentUser.id }
}

the request isn’'t authenticated, then the currentUser won’t exist on the context. In that case where you are trying to get authenticated info in a not authenticated request, you can:

import { AuthenticationError } from '@redwoodjs/api'

export const me: QueryResolvers['me'] = async (args, { context }) => {
  if (context.currentUser) {
    return { id: context.currentUser.id }
 }

 throw new AuthenticationError('Not allowed')
}

Hi dthyresson @grayson, it appears I didn’t @requireAuth on the me resolver. I’m now able to access context.currentUser.id.

One thing I’m noticing is that id on currentUser is on the current user type. It’d be nice to have that somehow.

Thank you both!

@willmruzek Glad it’s working!

As for the type of the CurrentUser that can depend on your implementation. For example, in Supabase the auth lib ships as:

/**
 * Represents the user attributes returned by the decoding the
 * Authentication provider's JWT together with an optional list of roles.
 */
type RedwoodUser = Record<string, unknown> & { roles?: string[] }

/**
 * ........ 
 * @returns RedwoodUser
 */
export const getCurrentUser = async (
  decoded,
  /* eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars */
  { token, type },
  /* eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars */
  { event, context }
): Promise<RedwoodUser> => {
  if (!decoded) {
    return null
  }

  const { roles } = parseJWT({ decoded })

  if (roles) {
    return { ...decoded, roles }
  }

  return { ...decoded }
}```

So, `getCurrentUser` is typed as a `RedwoodUser`. Which for Supabase is an object of JWT claims (plus role moved to top level).

Depending our what you return from `getCurrentUser` would should be able to type it and -- I think -- have `id ` and other properties available to you. 

If your user is a Prisma model then it can be that type.

Just as always if using Prisma, make sure no sensitive fields are added to that data returned as currentUser like password hash or salt.