
Securing your Apollo Client — Apollo Server Connection
Securing a connection between an Apollo Client and an Apollo Server is an essential part of any production-grade application. There are several ways to secure a connection, such as using HTTPS, using authentication, and authorization mechanisms, etc. In this article, we will focus on securing an Apollo Client connection to an Apollo Server using a JWT (JSON Web Token) authentication mechanism.
JSON Web Tokens (JWTs) are an industry-standard mechanism for representing claims securely between two parties. The JWT contains a header, a payload, and a signature. The header specifies the algorithm used to sign the token, the payload contains the claims (data), and the signature is used to verify that the message has not been tampered with.
To secure an Apollo Client connection to an Apollo Server, we need to do the following steps:
- Add the
jsonwebtoken
library to the Apollo Server project.
npm install jsonwebtoken
2. Create a middleware function that will authenticate the user using a JWT token.
// middleware.js
const jwt = require('jsonwebtoken');
const { AuthenticationError } = require('apollo-server');
const JWT_SECRET = 'mysecretkey';
const getUser = (token) => {
try {
if (token) {
return jwt.verify(token, JWT_SECRET);
}
return null;
} catch (err) {
throw new AuthenticationError('Invalid token');
}
};
const authMiddleware = ({ req }) => {
const token = req.headers.authorization || '';
const user = getUser(token.replace('Bearer ', ''));
return { user };
};
module.exports = authMiddleware;
This middleware function will extract the JWT token from the authorization header and verify the token using the jsonwebtoken
library. If the token is valid, it will return the user object; otherwise, it will throw an AuthenticationError
.
3. Add the middleware function to the Apollo Server.
// server.js
const { ApolloServer, gql } = require('apollo-server');
const authMiddleware = require('./middleware');
const typeDefs = gql`
type Query {
me: User
}
type User {
id: ID!
name: String!
email: String!
}
`;
const resolvers = {
Query: {
me: (parent, args, { user }) => {
return user;
},
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
context: authMiddleware,
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
We added the middleware function to the Apollo Server by passing it as the context
option. The context
function will be called with each request, and the result will be available in the resolver's third argument.
4. Add the JWT token to the Apollo Client requests.
// client.js
import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
const JWT_TOKEN = 'myjwttoken';
const httpLink = new HttpLink({ uri: 'http://localhost:4000' });
const authLink = setContext((_, { headers }) => {
return {
headers: {
...headers,
authorization: `Bearer ${JWT_TOKEN}`,
},
};
});
const client = new ApolloClient({
cache: new InMemoryCache(),
link: authLink.concat(httpLink),
});
client.query({ query: YOUR_QUERY }).then((data) => console.log(data));
We added the JWT token to the Apollo Client requests using the setContext
function from the @apollo/client/link/context
package. The setContext
function adds the authorization header with the token to the request headers.
The authorization header can then be verified on the server to determine if the user is authorized to make the request or not.
Now, let’s take a look at how we can verify the authorization header on the server.
Verifying the JWT Token on the Server
On the server, we can use a middleware to verify the JWT token in the authorization header of the incoming requests. We can use the jsonwebtoken package to decode the JWT token and verify its signature.
Here’s an example of how we can create a middleware to verify the JWT token on the server:
const jwt = require('jsonwebtoken');
const verifyToken = (req, res, next) => {
const authorizationHeader = req.headers['authorization'];
if (authorizationHeader) {
const token = authorizationHeader.split(' ')[1];
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (error) {
res.status(401).send({ error: 'Invalid token' });
}
} else {
res.status(401).send({ error: 'Unauthorized' });
}
};
In this example, we’re checking for the presence of the authorization header in the incoming requests. If the authorization header is present, we extract the JWT token from it and verify it using the jsonwebtoken package.
If the token is valid, we set the user property of the request object to the decoded token and call the next middleware in the chain.
If the token is invalid, we return a 401 Unauthorized response with an error message.
Conclusion
In this article, we learned how to secure an Apollo Client connection to an Apollo Server using JSON Web Tokens (JWT). We saw how to add the JWT token to the requests made by the Apollo Client using the setContext function from the @apollo/client/link/context package.
We also saw how to verify the JWT token on the server using a middleware that decodes and verifies the token using the jsonwebtoken package.
By securing our Apollo Client connection using JWT, we can ensure that only authorized users can make requests to our Apollo Server. This helps us to protect our server from unauthorized access and keep our data safe and secure.