Skip to content
Santekno.com | Tech Tutorials and Trends
EN
📖 0%
16 Aug 2025 · 5 min read ·Article 47 / 125
Go

47 Creating Login and Signup Mutations

IH
Ihsan Arif
Writer at Santekno · Backend Engineer

47 Creating Login and Signup Mutations

User authentication is the foundation of nearly every modern application. Security and efficiency in managing user identities are crucial, whether for a simple application or a complex one. In this 47th article of the series, I want to take a deep dive into how to build mutations for Login and Signup using GraphQL on Node.js, complete with sample code, simulations, and flow diagrams to make everything easier to understand.

Why Mutations?

Mutations in GraphQL are used to modify data on the server, making them a great fit for operations such as create (Signup) and update (Login—typically for authentication). Compared to a REST API, the GraphQL approach makes endpoints more elegant and explicit. This becomes especially valuable as an application grows and its requirements become more complex.


High-Level Architecture

Before diving into the code, let’s understand the architecture at a high level:

  • Frontend: Sends the login and signup mutations to the backend.
  • Backend: Provides the Schema and Resolvers for those mutations.
  • Database: Stores user data with encrypted (hashed) passwords.

Let’s illustrate the process with the following flow diagram.

MERMAID
graph TD
A[User] -->|Signup| B[GraphQL Mutation - signup]
B --> C[Resolver]
C --> D[Hash Password]
D --> E[Store to Database]
A2[User] -->|Login| F[GraphQL Mutation - login]
F --> G[Resolver]
G --> H[Verify Password]
H --> I[Return JWT Token]

Designing the GraphQL Schema

Let’s start by designing the basic schema for the Login and Signup mutations.

graphql
 1type Mutation {
 2  signup(username: String!, password: String!): AuthPayload!
 3  login(username: String!, password: String!): AuthPayload!
 4}
 5
 6type AuthPayload {
 7  token: String
 8  user: User
 9}
10
11type User {
12  id: ID!
13  username: String!
14}

Explanation:

  • signup and login return an AuthPayload object.
  • AuthPayload contains the JWT token and the user data.
  • The mutations accept username and password explicitly.

Implementation Code in Node.js

Tech Stack:

  • Node.js
  • Express.js
  • Apollo Server (GraphQL)
  • bcrypt (for hashing passwords)
  • jsonwebtoken (for generating JWTs)

Let’s assume we already have a connection to a MongoDB database.

1. User Model (MongoDB/Mongoose)

javascript
1// models/User.js
2const mongoose = require('mongoose');
3
4const userSchema = new mongoose.Schema({
5  username: { type: String, unique: true, required: true },
6  password: { type: String, required: true },
7});
8
9module.exports = mongoose.model('User', userSchema);

2. Implementing the Resolvers

Let’s look at the code logic for signup and login.

javascript
 1// resolvers.js
 2const bcrypt = require('bcryptjs');
 3const jwt = require('jsonwebtoken');
 4const User = require('./models/User');
 5
 6const SECRET = 'MY_SUPER_SECRET_KEY';
 7
 8const resolvers = {
 9  Mutation: {
10    signup: async (_, { username, password }) => {
11      // Check whether the user already exists
12      const existingUser = await User.findOne({ username });
13      if (existingUser) {
14        throw new Error('Username has been taken');
15      }
16
17      // Hash the password with bcrypt
18      const hashedPassword = await bcrypt.hash(password, 10);
19
20      // Create a new user
21      const user = new User({ username, password: hashedPassword });
22      await user.save();
23
24      // Generate a JWT token
25      const token = jwt.sign(
26        { userId: user.id, username: user.username },
27        SECRET,
28        { expiresIn: '7d' }
29      );
30
31      return {
32        token,
33        user
34      };
35    },
36
37    login: async (_, { username, password }) => {
38      const user = await User.findOne({ username });
39      if (!user) {
40        throw new Error('User not found');
41      }
42
43      const valid = await bcrypt.compare(password, user.password);
44      if (!valid) {
45        throw new Error('Invalid password');
46      }
47
48      const token = jwt.sign(
49        { userId: user.id, username: user.username },
50        SECRET,
51        { expiresIn: '7d' }
52      );
53
54      return {
55        token,
56        user
57      };
58    }
59  }
60};
61
62module.exports = resolvers;

Simulating Requests and Responses

Let’s look at real examples of requests and responses for these mutations.

1. Signup

Query

graphql
1mutation {
2  signup(username: "johndoe", password: "supersecret") {
3    token
4    user {
5      id
6      username
7    }
8  }
9}

Response

json
 1{
 2  "data": {
 3    "signup": {
 4      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
 5      "user": {
 6        "id": "649c22ebd58be255b9a38212",
 7        "username": "johndoe"
 8      }
 9    }
10  }
11}

2. Login

Query

graphql
1mutation {
2  login(username: "johndoe", password: "supersecret") {
3    token
4    user {
5      id
6      username
7    }
8  }
9}

Response

json
 1{
 2  "data": {
 3    "login": {
 4      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
 5      "user": {
 6        "id": "649c22ebd58be255b9a38212",
 7        "username": "johndoe"
 8      }
 9    }
10  }
11}

Mutation vs REST Comparison

FeatureGraphQL MutationREST API
EndpointA single “/graphql” endpointMany endpoints
Response DataTailored to the client’s requestFixed/limited
API EvolutionEasy to extendMore rigid
Error HandlingConsistent via the GraphQL responseDepends on the implementation

Best Practices

  • Hash Passwords: Always hash passwords with bcrypt before storing them in the database.
  • JWT Expiry: Include an expiration date on the JWT token for security.
  • Error Messages: Never expose sensitive error messages.
  • Input Validation: Validate the username and password on the backend.
  • Rate-Limit & Lockout: Implement rate limiting on the login endpoint to prevent brute-force attacks.

Potential Extensions

These mutations form the core foundation. There are many possible enhancements:

  • Password Reset
  • Email Verification
  • Social Login
  • Multi-Factor Authentication

Conclusion

Building login and signup mutations with GraphQL offers many advantages: efficiency, ease of extension, and more structured security. Clean code paired with a clear architecture strongly supports application scalability.

If you want to strengthen your application’s authentication system, understanding and implementing these two fundamental mutations is a very worthwhile investment. Happy experimenting, and don’t forget to add extra protection and validation in the next steps!


Related Articles

💬 Comments