Comprehensive Guide to koa-passport How to Implement Authentication in Koa.js

Introduction to koa-passport

koa-passport is an authentication middleware for Koa.js, which is a modern, scalable framework for building web applications. koa-passport integrates smoothly with any Koa application and provides a wide variety of authentication strategies to help you secure your applications.

API Examples

Basic Setup

    const Koa = require('koa');
    const bodyParser = require('koa-bodyparser');
    const session = require('koa-session');
    const passport = require('koa-passport');
    
    const app = new Koa();
    
    app.keys = ['secret-key'];
    app.use(session(app));
    app.use(bodyParser());
    app.use(passport.initialize());
    app.use(passport.session());
    
    app.listen(3000);
    console.log('Server running on http://localhost:3000');

Serialization

    passport.serializeUser((user, done) => {
      done(null, user.id);
    });

    passport.deserializeUser((id, done) => {
      // Assuming User is a model representing users in your DB
      User.findById(id, (err, user) => {
        done(err, user);
      });
    });

Local Strategy

    const LocalStrategy = require('passport-local').Strategy;

    passport.use(new LocalStrategy((username, password, done) => {
      // Assuming User is a model representing users in your DB
      User.findOne({ username: username }, (err, user) => {
        if (err) { return done(err); }
        if (!user) {
          return done(null, false, { message: 'Incorrect username.' });
        }
        if (!user.validPassword(password)) {
          return done(null, false, { message: 'Incorrect password.' });
        }
        return done(null, user);
      });
    }));

Routes

    const Router = require('koa-router');
    const router = new Router();

    router.get('/login', async (ctx) => {
      await ctx.render('login'); // Assuming you are using a templating engine
    });

    router.post('/login', 
      passport.authenticate('local', {
        successRedirect: '/profile',
        failureRedirect: '/login'
      })
    );

    app.use(router.routes()).use(router.allowedMethods());

Google OAuth Strategy

    const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;

    passport.use(new GoogleStrategy({
      clientID: 'GOOGLE_CLIENT_ID',
      clientSecret: 'GOOGLE_CLIENT_SECRET',
      callbackURL: 'http://localhost:3000/auth/google/callback'
    },
    (token, tokenSecret, profile, done) => {
      // Assuming User is a model representing users in your DB
      User.findOne({ googleId: profile.id }, (err, user) => {
        return done(err, user);
      });
    }));

    router.get('/auth/google',
      passport.authenticate('google', { scope: ['https://www.googleapis.com/auth/plus.login'] })
    );

    router.get('/auth/google/callback', 
      passport.authenticate('google', { failureRedirect: '/login' }),
      (ctx) => {
        ctx.redirect('/profile');
      });

Protected Routes

    function ensureAuthenticated(ctx, next) {
      if (ctx.isAuthenticated()) {
        return next();
      } else {
        ctx.redirect('/login');
      }
    }

    router.get('/profile', ensureAuthenticated, async (ctx) => {
      await ctx.render('profile', { user: ctx.state.user });
    });

Example Application

    const Koa = require('koa');
    const bodyParser = require('koa-bodyparser');
    const session = require('koa-session');
    const passport = require('koa-passport');
    const Router = require('koa-router');
    const LocalStrategy = require('passport-local').Strategy;

    const app = new Koa();
    const router = new Router();

    app.keys = ['secret-key'];
    app.use(session(app));
    app.use(bodyParser());
    app.use(passport.initialize());
    app.use(passport.session());

    // User model stub
    const users = [
      { id: 1, username: 'testUser', password: 'testPassword' }
    ];
    const User = {
      findOne: ({ username }) => users.find(user => user.username === username),
      findById: (id) => users.find(user => user.id === id),
      validPassword: (password) => users[0].password === password
    };

    passport.serializeUser((user, done) => done(null, user.id));
    passport.deserializeUser((id, done) => done(null, User.findById(id)));

    passport.use(new LocalStrategy((username, password, done) => {
      const user = User.findOne({ username });
      if (!user) return done(null, false, { message: 'Incorrect username.' });
      if (!user.validPassword(password)) return done(null, false, { message: 'Incorrect password.' });
      return done(null, user);
    }));

    router.get('/login', async (ctx) => {
      ctx.body = '
'; }); router.post('/login', passport.authenticate('local', { successRedirect: '/profile', failureRedirect: '/login' })); function ensureAuthenticated(ctx, next) { if (ctx.isAuthenticated()) return next(); ctx.redirect('/login'); } router.get('/profile', ensureAuthenticated, async (ctx) => { ctx.body = `

Hello ${ctx.state.user.username}

`; }); app.use(router.routes()).use(router.allowedMethods()); app.listen(3000, () => console.log('Server running on http://localhost:3000'));

Hash: 0af30059afb9c999ffd46e8ea9969b45e8ab236a395e0a27b3c28aa12382f142

Leave a Reply

Your email address will not be published. Required fields are marked *