Secure your full-stack application with Passport.js and OAuth 2.0: A TypeScript and Express tutorial
Implement secure authentication and authorisation in your full-stack app with Passport.js and TypeScript on an Express server.

Secure your full-stack application with Passport.js and OAuth 2.0: A TypeScript and Express tutorial

Introduction

This article will discuss implementing authentication and authorisation in a full-stack application using Passport.js with TypeScript on an Express server. We will focus on OAuth 2.0, a widely used authorisation framework that allows users to grant third-party access to their resources without sharing their credentials. We will also use TypeScript to benefit from its static typing and compile-time checks and Passport.js to simplify the authentication and authorisation process.

Setting up the development environment

Before implementing authentication and authorisation, we need to set up our development environment. We will use Node.js as our runtime environment, npm as our package manager, and Visual Studio Code as our code editor.

To create a new TypeScript project, run the following commands:

mkdir my-ap
cd my-app
npm init -y
npm install express body-parser cors passport passport-oauth2 express-session cookie-parser @types/express @types/passport @types/passport-oauth2 @types/cookie-parser @types/express-session typescript ts-node-dev nodemon --save-dev
tsc --init        

The above commands create a new directory named my-app, initialise a new npm project, install the necessary packages, and initialise a TypeScript configuration file named tsconfig.json.

We can now create an index.ts file in the root directory and set up an Express server:

import express, { Request, Response } from 'express'

const app = express();
const PORT = 3000;

app.get('/', (req: Request, res: Response) => {
  res.send('Hello World!');
});

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});;        

To run the server, execute the following command:

npx ts-node-dev index.ts        

You should see a message in the console indicating that the server is running.

Implementing authentication and authorisation

Now that we have set up our development environment and server, we can move on to implementing authentication and authorisation.

OAuth 2.0

OAuth 2.0 is an authorisation framework that allows users to grant third-party access to their resources without sharing their credentials. Instead, OAuth 2.0 uses tokens to authorise access, which users can revoke at any time.

To use OAuth 2.0, we need to create an OAuth 2.0 client ID and secret, which we can obtain from the service provider (e.g., Google, Facebook, Twitter). Once we have the client ID and secret, we can use Passport.js to authenticate and authorise users.

Passport.js

Passport.js is a popular authentication middleware for Node.js that provides a simple and flexible way to authenticate users with different strategies (e.g., OAuth, JWT, local). Passport.js supports TypeScript out of the box and provides type definitions for all its APIs.

To use Passport.js, we need to install the passport, passport-oauth2, express-session, and cookie-parser packages:

npm install passport passport-oauth2 express-session cookie-parser @types/passport @types/passport-oauth2 @types/cookie-parser @types/express-session --save        

Setting up Passport.js middleware

To set up Passport.js middleware, we need to create an instance of the Passport class, configure a session middleware, and initialize the passport.initialize() and passport.session() middleware functions:

import passport from 'passport'
import session from 'express-session';
import cookieParser from 'cookie-parser';

app.use(cookieParser());
app.use(session({
  secret: 'my-secret',
  resave: false,
  cookie: { secure: false },
})));
 
app.use(passport.initialize());
app.use(passport.session());        

To implement the authentication and authorisation flow, we need to configure a Passport.js strategy for OAuth 2.0, set up the routes for login and callback, and handle the authentication and authorisation errors.

To configure a Passport.js strategy for OAuth 2.0, we need to create an instance of the `OAuth2Strategy` class, passing in the client ID, client secret, and authorisation URL of the service provider:

import passport from 'passport'
import { OAuth2Strategy } from 'passport-oauth2';

passport.use(new OAuth2Strategy({
  authorizationURL: 'https://accounts.google.com/o/oauth2/v2/auth',
  tokenURL: 'https://oauth2.googleapis.com/token',
  clientID: process.env.GOOGLE_CLIENT_ID as string,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
  callbackURL: 'https://localhost:3000/auth/google/callback',
}, (accessToken, refreshToken, profile, done) => {
  // handle the user profile
  done(null, profile);
}));        

We also need to define a callback function that will be called after the user has authorised the application:

app.get('/auth/google/callback', passport.authenticate('oauth2', 
  successRedirect: '/',
  failureRedirect: '/login',
}));        

Setting up the routes for login and callback

To set up the routes for login and callback, we need to define two routes: one for the login page and one for the callback URL:

app.get('/login', (req, res) => 
  res.send(`
    <html>
      <body>
        <a href="/auth/google">Sign in with Google</a>
      </body>
    </html>
  `);
});

app.get('/auth/google', passport.authenticate('oauth2'));        

The /login route displays a link to the /auth/google route, which triggers the authentication process. The /auth/google route redirects users to the Google authorisation page, where they can grant or deny access to their resources.

Handling the authentication and authorisation errors

To handle the authentication and authorisation errors, we need to define an error handler middleware that will be called if an error occurs during the authentication or authorisation process:

app.use((err: any, req: Request, res: Response, next: Function) => 
  console.error(err.stack);
  res.status(500).send('An error occurred);
});        

Securing routes

We need to define a middleware function to secure routes that check whether the user is authenticated. If the user is authenticated, the middleware function should call the next() function to pass control to the next middleware function. Otherwise, the middleware function should redirect the user to the login page:

function isAuthenticated(req: Request, res: Response, next: Function) {
  if (req.isAuthenticated()) {
    return next();
  }

  res.redirect('/login');
}

app.get('/protected', isAuthenticated, (req, res) => {
  res.send('This is a protected route');
});        

The isAuthenticated() function checks whether the user is authenticated by calling the req.isAuthenticated() function provided by Passport.js. If the user is authenticated, the next() function is called to pass control to the next middleware function. If the user is not authenticated, the user is redirected to the login page.

Testing the application

To test the application, we must use a testing framework such as jest or mocha and an HTTP testing library such as supertest. We can write tests to ensure that the authentication and authorisation flow works correctly, and that the protected routes are secured.

import request from 'supertest'
import { app } from './index';

describe('Authentication and Authorization', () => {
  it('should redirect unauthenticated users to the login page', async () => {
    const res = await request(app).get('/protected');
    expect(res.status).toEqual(302);
    expect(res.header['location']).toEqual('/login');
  });

  it('should allow authenticated users to access protected routes', async () => {
    const agent = request.agent(app);
    await agent.get('/auth/google');
    const res = await agent.get('/protected');
    expect(res.status).toEqual(200);
    expect(res.text).toEqual('This is a protected route');
  });
});;        

The above test cases ensure that unauthenticated users are redirected to the login page when accessing protected routes, and that authenticated users can access protected routes without being redirected.

Conclusion

In this article, we have discussed how to implement authentication and authorisation in a full-stack application using Passport.js with TypeScript on an Express server. We have focused on OAuth 2.0 as the authorisation framework and have used Passport.js to simplify the authentication and authorisation process. We have also shown how to secure routes and test the application to ensure the authentication and authorisation flow works correctly. Following these best practices, you can create a secure and scalable full-stack application to authenticate and authorise users.

What topic should I cover next?

This article helps implement authentication and authorisation in your full-stack application using Passport.js and TypeScript on an Express server. Please let me know if you have any suggestions for what topic I should cover next. I'm always looking for new ideas to write about, and I value your feedback.

Join the daily dev rant community!

If you enjoyed this article and want to stay up-to-date with the latest trends and insights in full-stack development, join the Daily Dev Rant community. Daily Dev Rant is a community-driven platform for developers to share their experiences, challenges, and best practices. So sign up today and join the conversation!

#fullstackdevelopment #typescript #express #passportjs #oauth2 #authentication #authorization #webdevelopment #nodejs #backenddevelopment #developers #codingtips #devcommunity #webdev #programming #tech

Em Gulliver

Product Manager @ Paperly | Founder @ MEGGI.

2 年

This is really easy to understand and read. I’m going to use this for my current project I’m working on! Thanks Novin!?

Tyrell Blackburn

Frontend Developer at Sydney Opera House | Building Seamless User Experiences with React.js, TypeScript, Node.js, and Drupal

2 年

Great article Novin. I'll reference this when I implement auth in my next project.

Jon Holland

I build teams | Associate Director | Tech Recruitment @ The Onset

2 年

This is awesome Novin! Any devs in my network, take a look ??

要查看或添加评论,请登录

Novin Noori的更多文章

社区洞察

其他会员也浏览了