Implementing Authentication
1. Validating JWT Tokens
Example: JWT verification middleware
import jwt from "jsonwebtoken";
async function verifyJWT(authHeader) {
if (!authHeader?.startsWith("Bearer ")) return null;
try {
const payload = jwt.verify(authHeader.slice(7), process.env.JWT_SECRET, {
algorithms: ["RS256"], audience: "api", issuer: "auth-service"
});
return await db.user.findUnique({ where: { id: payload.sub } });
} catch { return null; }
}
2. Adding User to Context
| Step | Detail |
|---|---|
| Extract token | Authorization header (Bearer) or cookie |
| Verify | Check signature, expiry, audience |
| Hydrate | Optionally fetch full user from DB |
| Attach | context.user |
3. Protecting Resolvers
Example: Auth helper
function requireAuth(ctx) {
if (!ctx.user) throw new GraphQLError("Unauthenticated", { extensions: { code: "UNAUTHENTICATED" } });
return ctx.user;
}
Mutation: { createPost: (_, { input }, ctx) => { const u = requireAuth(ctx); ... } }
4. Creating Auth Directives
| Directive | Behavior |
|---|---|
| @auth | Require any authenticated user |
| @auth(requires: ROLE) | Require specific role |
| @public | Mark as bypassing auth |
5. Handling Unauthenticated Requests
| Approach | Detail |
|---|---|
| Throw UNAUTHENTICATED | For required fields |
| Return null | For optional viewer |
| HTTP 401 | Set via extensions.http (Yoga/v4) |
6. Implementing Login Mutation
Example: Login
login: async (_, { email, password }, { db }) => {
const user = await db.user.findUnique({ where: { email } });
if (!user || !(await bcrypt.compare(password, user.passwordHash))) {
return { __typename: "InvalidCredentials", message: "Invalid email or password" };
}
return { __typename: "LoginSuccess", user, token: signJWT(user), refreshToken: signRefresh(user) };
}
7. Implementing Logout Mutation
| Strategy | Detail |
|---|---|
| Stateless JWT | Client discards token; server can't revoke |
| Token blocklist | Add jti to Redis until exp |
| Refresh token rotation | Invalidate refresh in DB |
| Cookie-based | Clear-Site-Data header |
8. Refreshing Access Tokens
Example: Refresh mutation
type Mutation {
refreshAccessToken(refreshToken: String!): TokenPair!
}
type TokenPair { accessToken: String!, refreshToken: String!, expiresIn: Int! }
9. Using Session-based Auth
| Pattern | Detail |
|---|---|
| HTTP-only cookie | Session id stored in Redis/DB |
| CSRF protection | SameSite=Strict, custom header |
| Server revocation | Easy — delete server-side session |
10. Implementing Social Auth
| Provider | Library |
|---|---|
| OAuth/OIDC | passport, NextAuth, Auth.js, Authelia |
| Federated | Auth0, Clerk, Cognito, Firebase Auth |
| GraphQL flow | Mutation exchanges OAuth code → JWT |