Actualmente estoy en un proceso de aprendizaje con React, GraphQL, MongoDB. La verdad que a veces se me hace difícil llevarle el ritmo a algunas tecnologías. Peleé mucho con desplegar MongoDB en Heroku, pero me costó un poco más el tema de autenticación con GraphQL y Apollo.
En este post voy a dar por hecho que ya se tiene un sistema de login y registro y me voy a saltar directamente a preparar todo para la autenticación de usuarios con GraphQL usando Apollo 3. Antes de eso estuve usando react-apollo y apollo-boots, pero ya habia pasado mucho tiempo y era dificil encontrar algun tipo de soporte, así que tuve que migrar todo a la última versión de Apollo.

Comenzamos:
Frontend: Preparando autenticación con GraphQL y Apollo
Primero empezamos preparando todo para enviar los datos que recibimos desde algún tipo de formulario de login y cuyos datos después de verificar usuario y contraseña guardamos un token en el LocalStorage. Dicho token tenemos que enviarlo hacia el servidor para hacer la autenticación del usuario.
import { ApolloClient, InMemoryCache, HttpLink} from "@apollo/client";
import { setContext } from '@apollo/client/link/context';
const httpLink = new HttpLink({
uri: 'http://localhost:4000/graphql',
fetchOptions: {
credentials: 'include'
}
});
const authLink = setContext((_, { headers })=> {
const token = localStorage.getItem('token')
return {
headers: {
...headers,
authorization: token ? token : ""
}
}
})
export const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache({
addTypename: false
}
),
});
Lo que estoy haciendo es llevar todo lo que hay en el localStorage con setContext
Backend: Haciendo la autenticación
Si bien con Apollo/Client enviamos el contexto el token que obtuvimos desde el localStorage en Apollo Server debemos recibir, verificar que el token sea el correcto y enviar una respuesta, sea un error o guardar dichos datos para compararlo despues en un resolver.
import express, { request } from 'express'
import cors from 'cors'
import { ApolloServer } from 'apollo-server-express';
import dotenv from 'dotenv'
import jwt from 'jsonwebtoken'
import { typeDefs } from './data/schema.js';
import { resolvers } from './data/resolvers.js'
dotenv.config({path: 'variables.env'})
const app = express();
const corsOptions = {
origin: 'http://localhost:3000',
credentials: true
}
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: true,
playground: true,
context: async ({req}) => {
const token = req.headers.authorization;
if(token !== null){
try{
const userActual = await jwt.verify(token, process.env.SECRET)
return userActual
} catch(err) {
console.error(err)
}
}
}
});
server.applyMiddleware({app, cors: corsOptions});
app.listen(process.env.PORT || 4000,
() => console.log("Server is running"))
Si notan un poco, este pedazo de codigo, se parece mucho al post de mongoDB en Heroku, y es porque es el mismo proyecto.
En ApolloServer agregamos contexto y recibimos aquello que enviamos desde el Frontend lo guardamos en una variable llamada token. Lo comparamos y verificamos con JWT para la autenticación y esto lo guardamos en el request (creo que lo guardamos en el request 😐 )
Resolvers
Hasta aqui hemos enviado el token desde el frontend y lo comparamos y guardamos en el servidor. Ahora toca recibir dichos datos que se enviaba en el token y buscando en la base de datos y retornar dichos datos.
Para ello en resolvers creamos un nuevo QUERY con lo siguiente
getUser:(root, args, context) => {
if(!context){
return null
}
const user = User.findOne({ email: context.email})
return user
}
Ahora si tenemos algo resolver.js tambien debemos tenerlo en el Schema.
type Query {
getUser : User
}
type User {
name: String,
lastname: String,
email: String,
password: String,
role: String
}
Ahora creo que es más fácil entender que pasa en el Resolver.
Lo que recibimos en el token es el usuario con el hacen login en nuestro sistema y este pasa por los diferentes contextos y lo recibimos en el resolver y es ahí donde buscamos y devolvemos un usuario registrado en nuestra base de datos.
Creo que es un poco complejo este tema de autenticación con React y Apollo o bueno, al menos lo fue para mi. Algo que ayuda tambien mucho la documentacion de Apollo pero a veces falta un poco de explicación al respecto.
Espero que haya sido de ayuda y puedan continuar con su proyecto, así como yo avanzo con el mio.
[…] PD: Para este caso estaré usando {user} que tengo como contexto en la autenticación de usuarios con GraphQL […]