Autenticación con GraphQL y Apollo en React

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.

Autenticación con GraphQL y Apollo en React

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.

Un comentario

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *