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.

Imagen por defecto
Appatico
Artículos: 17

Deja un comentario