⚠️
This is the documentation for the old GraphQL Yoga version 4. We recommend upgrading to the latest GraphQL Yoga version 5.

Migrate to GraphQL Yoga v5

JWT

A JSON Web Tokens (JWT) is a signed token containing arbitrary informations, commonly used for authentication. By being signed by the issuer of the token, it can be verified that the token is valid and has not been tampered with.

GraphQL Yoga provides a plugin to easily integrate JWT into your API.

Installation

npm i @graphql-yoga/plugin-jwt

Usage

import { createSchema, createYoga } from 'graphql-yoga'
import jwt from 'jsonwebtoken'
import { useJWT } from '@graphql-yoga/plugin-jwt'
import { getUserById, getUserByLogin } from './db'
 
const signingKey = process.env.JWT_SECRET
 
const yoga = createYoga({
  schema: createSchema({
    typeDefs: `
      type Query {
        me: User
      }
 
      type Mutation {
        login(email: String!, password: String!): String
      }
    `,
 
    resolvers: {
      Query: {
        me: (parent, args, ctx) => {
          // The content of the JWT can be found in the context
          if (!ctx.jwt) {
            // No JWT token provided, we are not authenticated
            return null
          }
          return getUserById(ctx.jwt.sub)
        }
      },
      Mutation: {
        login: (parent, { email, password }) => {
          const user = getUserByLogin(email, password)
          if (!user) {
            throw new GraphqlError('Invalid credentials')
          }
 
          // Client will receive a JWT token, it will then can be used in 'authorization' header
          return jwt.sign({ username: user.name }, signingKey, {
            subject: user.id
          })
        }
      }
    }
  }),
  plugins: [
    useJWT({
      issuer: 'http://graphql-yoga.com',
      signingKey
    })
  ]
})
 
const server = createServer(yoga)
server.listen(4000, () => {
  console.log(`Server is running on http://localhost:4000/${server.graphqlEndpoint}`)
})

Usage with Cookies

Security best practices recommend to store JWT in a HTTP-only cookie. This way, the token cannot be accessed by JavaScript and is only sent to the server on each request.

To do so, you can use the getToken option of the plugin to extract the token from the request’s cookies.

import { createSchema, createYoga } from 'graphql-yoga'
import jwt from 'jsonwebtoken'
import { useJWT } from '@graphql-yoga/plugin-jwt'
import { useCookies } from '@whatwg-node/server-plugin-cookies'
import { getUserById, getUserByLogin } from './db'
 
const signingKey = process.env.JWT_SECRET
 
const yoga = createYoga({
  schema: createSchema({
    typeDefs: `
      type Query {
        me: User
      }
 
      type Mutation {
        login(email: String!, password: String!): String
      }
    `,
 
    resolvers: {
      Query: {
        me: (parent, args, ctx) => {
          // The content of the JWT can be found in the context
          if (!ctx.jwt) {
            // No JWT token provided, we are not authenticated
            return null
          }
          return getUserById(ctx.jwt.sub)
        }
      },
      Mutation: {
        login: (parent, { email, password }, ctx) => {
          const user = getUserByLogin(email, password)
          if (!user) {
            throw new GraphqlError('Invalid credentials')
          }
 
          const token = jwt.sign({ username: user.name }, signingKey, {
            subject: user.id
          })
 
          // Set the cookie on the response
          ctx.request.cookieStore?.set({
            name: 'authorization',
            sameSite: 'strict',
            secure: true,
            domain: 'graphql-yoga.com',
            expires: new Date(Date.now() + 1000 * 60 * 60 * 24),
            value: token,
            httpOnly: true
          })
        }
      }
    }
  }),
  plugins: [
    useCookies(),
    useJWT({
      issuer: 'http://graphql-yoga.com',
      signingKey,
      getToken: ({ request }) => request.cookieStore?.get('authorization')
    })
  ]
})
 
const server = createServer(yoga)
server.listen(4000, () => {
  console.log(`Server is running on http://localhost:4000/${server.graphqlEndpoint}`)
})