Skip to content

Commit 5502158

Browse files
committed
graphql api with jwt auth
0 parents  commit 5502158

File tree

7 files changed

+210
-0
lines changed

7 files changed

+210
-0
lines changed

.env

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
MONGO_URI="mongodb+srv://user1:1234@cluster0.2r9byhz.mongodb.net/?retryWrites=true&w=majority"
2+
SECRET_KEY = 'mySecretKey';

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules*/
2+
3+
package-lock.json

graphql/resolvers.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
const User = require("../models/user");
2+
const jwt = require('jsonwebtoken');
3+
const secretKey = process.env.SECRET_KEY;
4+
5+
// Function to generate a JWT
6+
function generateToken(user) {
7+
const token = jwt.sign({ id: user.id, role: user.role }, secretKey, { expiresIn: '1h', algorithm: 'HS256' });
8+
return token;
9+
}
10+
11+
// Function to verify token
12+
function verifyToken(token) {
13+
if (!token) {
14+
throw new Error('Token not provided');
15+
}
16+
17+
try {
18+
const decoded = jwt.verify(token, secretKey, { algorithms: ['HS256'] });
19+
return decoded;
20+
} catch (err) {
21+
throw new Error('Invalid token');
22+
}
23+
}
24+
25+
// GraphQL Resolvers
26+
const resolvers = {
27+
Mutation: {
28+
register: async (_, { userInput: { name, password, role } }) => {
29+
if (!name || !password || !role) {
30+
throw new Error('Name password, and role required');
31+
}
32+
33+
const newUser = new User({
34+
name: name,
35+
password: password,
36+
role: role,
37+
});
38+
39+
try {
40+
const response = await newUser.save();
41+
return {
42+
id: response._id,
43+
...response._doc,
44+
};
45+
} catch (error) {
46+
console.error(error);
47+
throw new Error('Failed to create user');
48+
}
49+
},
50+
51+
login: async (_, { name, password }) => {
52+
try {
53+
const user = await User.findOne({ name: name });
54+
if (!user) {
55+
throw new Error('User not found');
56+
}
57+
if (password !== user.password) {
58+
throw new Error('Incorrect password');
59+
}
60+
const token = generateToken(user);
61+
if (!token) {
62+
throw new Error('Failed to generate token');
63+
}
64+
return {
65+
message: 'Login successful',
66+
token: token,
67+
};
68+
} catch (error) {
69+
console.error(error);
70+
throw new Error('Login failed');
71+
}
72+
}
73+
},
74+
Query: {
75+
users: async (parent, args, context) => {
76+
try {
77+
// Extract the token from the request headers
78+
const token = context.req.headers.authorization || '';
79+
80+
81+
const decodedToken = verifyToken(token);
82+
if (decodedToken.role !== 'Admin') {
83+
throw new ('Unauthorized. Only Admins can access this data.');
84+
}
85+
const users = await User.find({}, { name: 1, _id: 1, role: 1 });
86+
return users;
87+
} catch (error) {
88+
console.error(error);
89+
throw new Error('Failed to fetch users');
90+
}
91+
},
92+
},
93+
};
94+
95+
module.exports = resolvers;

graphql/typeDefs.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
const { gql } = require("apollo-server");
2+
3+
const typeDefs = gql`
4+
type User {
5+
id: ID!
6+
name: String!
7+
password: String!
8+
role: String!
9+
}
10+
11+
input UserInput {
12+
name: String!
13+
password: String!
14+
role: String!
15+
}
16+
17+
type TokenResult {
18+
message: String
19+
token: String
20+
}
21+
22+
type Query {
23+
users: [User]
24+
}
25+
26+
type Mutation {
27+
register(userInput: UserInput): User
28+
login(name: String!, password: String!, role: String!): TokenResult
29+
}
30+
`;
31+
32+
module.exports = typeDefs;

models/user.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const {model, Schema} = require('mongoose');
2+
3+
4+
const userSchema = new Schema({
5+
name: String,
6+
password: String,
7+
role : String
8+
9+
});
10+
11+
12+
module.exports = model('user', userSchema);

package.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "graphql-mongodb-jwt",
3+
"version": "1.0.0",
4+
"main": "index.js",
5+
"scripts": {
6+
"test": "echo \"Error: no test specified\" && exit 1",
7+
"start": "node server.js"
8+
},
9+
"author": "",
10+
"license": "ISC",
11+
"dependencies": {
12+
"apollo-server": "^3.12.0",
13+
"dotenv": "^16.3.1",
14+
"express": "^4.18.2",
15+
"graphql": "^16.6.0",
16+
"jsonwebtoken": "^9.0.2",
17+
"mongoose": "^7.0.3"
18+
},
19+
"keywords": [],
20+
"description": ""
21+
}

server.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
const { ApolloServer } = require('apollo-server');
2+
const mongoose = require('mongoose');
3+
require('dotenv').config();
4+
5+
6+
7+
8+
9+
10+
const typeDefs = require("./graphql/typeDefs");
11+
const resolvers = require("./graphql/resolvers");
12+
13+
14+
15+
const server = new ApolloServer({
16+
typeDefs,
17+
resolvers ,
18+
context: ({ req }) => ({ req }),
19+
});
20+
21+
22+
23+
const MONGO_URI = process.env.MONGO_URI;
24+
25+
mongoose
26+
.connect(MONGO_URI, {
27+
useNewUrlParser: true,
28+
useUnifiedTopology: true,
29+
})
30+
.then(() => {
31+
console.log("Connected to DB");
32+
return server.listen({ port: 5000 });
33+
})
34+
.then((res) => {
35+
console.log(`Server running at ${res.url}`);
36+
37+
})
38+
.catch(err => {
39+
console.log(err.message);
40+
41+
});
42+
43+
44+
45+

0 commit comments

Comments
 (0)