Custom OAuth Server From Scratch Server for authentication
Custom OAuth Server from scratch
Introduction
OAuth is an open standard for access delegation, commonly used as a way for Internet users to grant websites or applications access to their information on other websites but without giving them the passwords. In this article, we will learn how to create a custom OAuth server using Node.js and Express.js with MongoDB and Inertia.js for client/views.
I am writing this article to demostrate only and highly focusing on KISS (Keep It Simple and Stupid). So, begginers or anyone reading this can understand the picture of it easily.
Prerequisites
Before we get started, make sure you have the following installed on your machine:
- Node.js
- TypeScript (Recommended, but not using in this time)
- MongoDB
- Express.js (Node.js web application framework)
- Vue & Inertia.js (SSR approach)
Step 1: Create a new Node.js project
First, create a new Node.js project using the following command:
mkdir custom-oauth-server
cd custom-oauth-server
npm init -y
Step 2: Install the required dependencies
Next, install the required dependencies for our project:
npm install express mongoose passport passport-oauth2-client-password
Step 3: Create a new Express.js server
Create a new file called server.js
and add the following code:
const express = require('express');
const mongoose = require('mongoose');
const passport = require('passport');
const ClientPasswordStrategy = require('passport-oauth2-client-password').Strategy;
const app = express();
app.use(express.json());
mongoose.connect('mongodb://localhost:27017/oauth', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const Client = mongoose.model('Client', new mongoose.Schema({
clientId: String,
clientSecret: String,
}));
passport.use(new ClientPasswordStrategy(
function(clientId, clientSecret, done) {
Client.findOne({ clientId: clientId, clientSecret: clientSecret }, function(err, client) {
if (err) { return done(err); }
if (!client) { return done(null, false); }
return done(null, client);
});
}
));
app.post('/oauth/token', passport.authenticate('oauth2-client-password', { session: false }), (req, res) => {
res.json({ access_token });
});
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});
Step 4: Create a new MongoDB database
Create a new MongoDB database called oauth
and add a new collection called clients
with the following fields:
clientId
(String)clientSecret
(String)
Step 5: Start the Express.js server
Start the Express.js server using the following command:
node server.js
Step 6: Test the OAuth server
You can test the OAuth server using Postman or any other API testing tool. Send a POST
request to http://localhost:3000/oauth/token
with the following parameters:
client_id
(String)client_secret
(String)
If the client credentials are valid, the server will return an access token.
Step 7: Implement the client-side view using Inertia.js
Create a new Vue.js project using the following command:
npx create-vue-app client
Install the required dependencies for Inertia.js:
npm install @inertiajs/inertia @inertiajs/inertia-vue @inertiajs/progress vue
Create a new file called app.js
and add the following code:
Following SSR approach using Inertia.js
import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/inertia-vue';
createInertiaApp({
resolve: name => require(`./src/views/${name}`),
setup({ el, App, props }) {
createApp({ render: () => h(App, props) }).mount(el);
},
});
Create a new file called index.vue
in src/views
and add the following code:
<template>
<div>
<h1>OAuth Server</h1>
<form @submit.prevent="submit">
<input type="text" v-model="clientId" placeholder="Client ID">
<input type="text" v-model="clientSecret" placeholder="Client Secret">
<button type="submit">Submit</button>
</form>
</div>
</template>
<script>
export default {
data() {
return {
clientId: '',
clientSecret: '',
};
},
methods: {
async submit() {
const response = await fetch('http://localhost:3000/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
client_id: this.clientId,
client_secret: this.clientSecret,
}),
});
const data = await response.json();
console.log(data);
},
},
};
</script>
Step 8: Start the application
Start the application using the following command:
npm run dev
You can now access the application at http://localhost:3000
.
It should display a form with two input fields for the client ID and client secret. When you submit the form, it will send a POST
request to the OAuth server and return an access token.
Step 9: Implement Users and Scopes
You can extend the OAuth server to support users and scopes by adding the following fields to the Client
model:
userId
(String)scopes
(Array)
You can then update the ClientPasswordStrategy
to validate the user and scopes when authenticating the client.
passport.use(new ClientPasswordStrategy(
function(clientId, clientSecret, done) {
Client.findOne
({ clientId: clientId, clientSecret: clientSecret }, function(err, client) {
if (err) { return done(err); }
if (!client) { return done(null, false); }
if (client.userId !== req.body.user_id) { return done(null, false); }
if (!client.scopes.includes(req.body.scope)) { return done(null, false); }
return done(null, client);
});
}
));
You can then update the POST
request to include the user_id
and scope
parameters.
const response = await fetch('http://localhost:3000/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
client_id: this.clientId,
client_secret: this.clientSecret,
user_id: this.userId,
scope: this.scope,
}),
});
You can now test the OAuth server with users and scopes.
Why Custom OAuth Server?
- Customization: You can customize the OAuth server to meet your specific requirements.
- Security: You have full control over the security of the OAuth server.
- Scalability: You can scale the OAuth server as needed to handle a large number of clients and users.
- Integration: You can integrate the OAuth server with other systems and services.
If you want to create an OAuth server for a private organization, you can customize the server to meet the organization’s specific requirements and integrate it with the organization’s existing systems and services. For example, government organizations, financial institutions, and healthcare providers can create custom OAuth servers to secure their data and services without relying on third-party providers.
Conclusion
In this article, we learned how to create a custom OAuth server using Node.js and Express.js with MongoDB. We also learned how to authenticate clients using the OAuth 2.0 client password strategy. I hope you found this article helpful. If you have any questions or feedback, feel free to reach out to me.
If you have any questions or feedback, feel free to reach out to me on Github or Email Me.