• Stars
    star
    1,630
  • Rank 28,707 (Top 0.6 %)
  • Language
  • Created over 6 years ago
  • Updated almost 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Documentation for Passport.js.

Passport: The Hidden Manual

Table of Contents

Intro

The official passport documentation has a long, example driven style. Some people like that. Some people, on the other hand, want to know "when I call this function, what's it going to do?" This is for those people.

If you find inaccuracies, please feel free to open an issue or a PR.

Passport class

When you import 'passport', you get back an instance of the "Passport" class. You can create new passport instances:

import passport from 'passport';

const myPassport = new passport.Passport();

You'd want to do this if you want to use Passport in a library, and you don't want to pollute the "global" passport with your authentication strategies.

passport.initialize()

Returns a middleware which must be called at the start of connect or express based apps. This sets req._passport, which passport uses all over the place. Calling app.use(passport.initialize()) for more than one passport instance will cause problems.

(Prior to v0.5.1, this would also set up req.login() and req.logout(), but this has been moved to passport.authenticate().)

passport.session([options])

"If your application uses persistent login sessions, passport.session() middleware must also be used." Should be after your session middleware.

This returns a middleware which will try to read a user out of the session; if one is there, it will store the user in req.user, if not, it will do nothing. Behind the scenes, this:

app.use(passport.session());

is actually the same as:

app.use(passport.authenticate('session'));

which is using the built-in "session strategy". You can customize this behavior by registering your own session strategy.

session() does take an 'options' object. You can set pass {pauseStream: true} to turn on a hacky work-around for problems with really old node.js versions (pre-v0.10). Never set this true.

passport.authenticate(strategyName[, options][, callback])

strategyName is the name of a strategy you've previously registered with passport.use(name, ...). This can be an array, in which case the first strategy to succeed, redirect, or error will halt the chain. Auth failures will proceed through each strategy in series, failing if all fail.

This function returns a middleware which runs the strategies. If one of the strategies succeeds, this will set req.user. If you pass no options or callback, and all strategies fail, this will write a 401 to the response. Note that some strategies may also cause a redirect (OAuth, for example). This middleware also adds helper functions to the req object: req.login(), req.logout(), and req.isAuthenticated().

Valid options:

  • successRedirect - path to redirect to on a success.
  • failureRedirect - path to redirect to on a failure (instead of 401).
  • failureFlash - True to flash failure messages or a string to use as a flash message for failures (overrides any from the strategy itself).
  • successFlash - True to flash success messages or a string to use as a flash message for success (overrides any from the strategy itself).
  • successMessage - True to store success message in req.session.messages, or a string to use as override message for success.
  • failureMessage - True to store failure message in req.session.messages, or a string to use as override message for failure.
  • session - boolean, enables session support (default true)
  • failWithError - On failure, call next() with an AuthenticationError instead of just writing a 401.

Note that the entire options object will be passed on to the strategy as well, so there may be extra options you can pass here defined by the strategy. For example, you can pass a callbackURL along to an oauth strategy.

callback is an (err, user, info) function. No req, res, or next, because you're supposed to get them from the closure. If authentication fails, user will be false. If authentication succeeds, your callback is called and req.user is NOT set. You need to set it yourself, via req.login():

app.post('/login', function(req, res, next) {
    passport.authenticate('local', function(err, user, info) {
        if (err) { return next(err); }
        if (!user) { return res.redirect('/login'); }

    // NEED TO CALL req.login()!!!
        req.login(user, next);
    })(req, res, next);
});

Don't just set req.user = user, since this won't update your session.

passport.authorize(strategyName[, options], callback)

This isn't really well named, as it has nothing to do with authorization. This function is exactly like passport.authenticate(), but instead of setting req.user, it sets req.account, and it doesn't make any changes to the session.

This is here so if you want to do something like "Link my account to OtherService", you can have a user who is already logged in, and use Passport to retreive their OtherService credentials. Useful for linking to social media platforms and such.

passport.use([strategyName,] strategy)

Configure a strategy. Strategies have a "default name" assigned to them, so you don't have to give them a name.

passport.serializeUser(fn(user, done) | fn(req, user, done))

Passport will call this to serialize the user to the session whenever you login a user with req.login(), or whenever a user is authenticated via passport.authenticate(). The function you pass in should call done(null, serializedUser).

What this is going to do is set req.session.passport.user = serializedUser. Traditionally you'd make serializedUser some sort of string, like a user ID which you can fetch from your DB. Assuming whatever sessions middleware you're using can store arbitrary objects, though, you can make serializedUser an arbitrary JSON object. If your session middleware is writing the session to a client side cookie (like a JWT session that's stored in a cookie, or client-sessions), then don't store anything too huge in here - browsers will ignore your cookie if it's too big.

Undocumented: The fn() you pass can be a fn(req, user, done). If multiple serializers are registered, they are called in order. Can return 'pass' as err to skip to next serialize.

passport.deserializeUser(fn(serializedUser, done) | fn(req, serializedUser, done))

Passport will call this to deserialize the user from the session. Should call done(null, user). The serializedUser is req.session.passport.user.

It can happen that a user is stored in the session, but that user is no longer in your database (maybe the user was deleted, or did something to invalidate their session). In this case, the deserialize function should pass null or false for the user, not undefined.

Undocumented: fn() can be a fn(req, id, done). As with serializeUser, serializers are called in order.

Strategies

Writing custom strategies

Write a custom strategy by extending the SessionStrategy class from passport-strategy. You can unit test a strategy in isolation with passport-strategy-runner.

import Strategy from 'passport-strategy';

export default class SessionStrategy extends Strategy {
    constructor() {
        super();

        // Set the default name of our strategy
        this.name = 'session';
    }

    /**
     * Authenticate a request.
     *
     * This function should call exactly one of `this.success(user, info)`, `this.fail(challenge, status)`,
     * `this.redirect(url, status)`, `this.pass()`, or `this.error(err)`.
     * See https://github.com/jaredhanson/passport-strategy#augmented-methods.
     *
     * @param {Object} req - Request.
     * @param {Object} options - The options object passed to `passport.authenticate()`.
     * @return {void}
     */
    authenticate(req, options) {
        if(req.cookie.apikey === '6398d011-d80f-4db1-a36a-5dcee2e259d0') {
        this.success({username: 'dave'});
    } else {
        this.fail();
    }
    }
}

Note when calling fail(), the challenge should be either a challenge string as defined by RFC 7235 S2.1, suitable for including in a WWW-Authenticate header, or else a {message, type} object, were message is the message to use a a "flash message", and type is the flash type (defaults to 'error').

Verify Callback

Passport strategies require a verify callback, which is generally a (err, user, options?) object. options.message can be used to give a flash message. user should be false if the user does not authenticate. err is meant to indicate a server error, like when your DB is unavailable; you shouldn't set err if a user fails to authenticate.

Functions added to the Request

req.login(user, callback)

Log a user in (causes passport to serialize the user to the session). On completion, req.user will be set.

req.logout()

Removes req.user, and clears the session.passport value from the session.

Passport and Sessions

Passport creates a key in the session called session.passport.

When a request comes in to the passport.session() middleware, passport runs the built-in 'session' strategy - this calls deserializeUser(session.passport.user, done) to read the user out of the session, and stores it in req.user.

You can override how passport deserializes a session by creating a new strategy called 'session' and registering it with passport.use().

When you call req.login(), or when a strategy successfully authenticates a user, passport uses the session manager, and essentially does:

serializeUser(req.user, (err, user) => {
    if(err) {return done(err);}
    session.passport.user = user;
});

Although it's more verbose about it. You can override the session manager by creating your own implementation and setting passport._sm, but this is not documented or supported, so use at your own risk.

More Repositories

1

node-amqp-connection-manager

Auto-reconnect and round robin support for amqplib.
TypeScript
526
star
2

gchalk

Terminal string styling for go done right, with full and painless Windows 10 support.
Go
334
star
3

gh-find-current-pr

Github Action for finding the Pull Request (PR) associated with the current SHA.
TypeScript
169
star
4

rust-book-abridged

An abridged version of "The Rust Programming Language"
JavaScript
86
star
5

node-promise-breaker

Helps you write libraries that accept both promises and callbacks.
JavaScript
85
star
6

gh-ecr-push

GitHub Action to push a docker image to Amazon ECR.
TypeScript
74
star
7

node-supertest-fetch

Supertest-like testing with a WHAT-WG fetch interface.
TypeScript
39
star
8

go-supportscolor

Detects whether a terminal supports color, and enables ANSI color support in recent Windows 10 builds.
Go
35
star
9

gh-docker-logs

GitHub Action to collect logs from all docker containers.
TypeScript
28
star
10

lol-js

node.js bindings for the Riot API for League of Legends
CoffeeScript
26
star
11

node-heapsnapshot-parser

node-heapsnapshot-parser
JavaScript
19
star
12

kitsch

The extremely customizable and themeable shell prompt.
Go
17
star
13

kube-auth-proxy

Securely expose your private Kubernetes services.
TypeScript
14
star
14

gh-ecr-login

GitHub action to login to Amazon ECR
TypeScript
10
star
15

winston-format-debug

Debug formatter for Winston
TypeScript
6
star
16

use-css-transition

A react hook for applying CSS transitions to multiple elements.
TypeScript
5
star
17

passport-strategy-runner

Run a Passport strategy without Passport.
TypeScript
5
star
18

solox

MobX without the mob! A state management library for React.
TypeScript
4
star
19

immer-ente

State management for React, made easy
TypeScript
4
star
20

bunyan-debug-stream

Output stream for Bunyan which prints human readable logs.
TypeScript
4
star
21

tsheredoc

Heredocs for javascript and typescript.
TypeScript
4
star
22

node-jwalton-logger

TypeScript
3
star
23

node-swagger-template

"Template project for building Swagger APIs on Node.js
JavaScript
2
star
24

chai-jest

Chai bindings for jest mocks.
TypeScript
2
star
25

octranspo_fetch

Ruby gem for fetching data from the OC Transpo API
Ruby
2
star
26

environment

My bash scripts and such.
Shell
2
star
27

gh-for-each-pr

A GitHub action that runs a command for each matching PR.
TypeScript
1
star
28

pixdl

Image album downloader, written in golang
Go
1
star
29

docker-armagetron

Docker image for dedicated Armagetron server
1
star
30

arduino-dancepad

Turns an Arduino Leonardo (or similar) into a keyboard controller for StepMania.
C++
1
star
31

rust-tokio-task-tracker

A simple graceful shutdown solution for tokio.
Rust
1
star
32

node-events-listener

Listen to events from a Node.js EventEmitter.
JavaScript
1
star
33

babel-plugin-private-class-fields-to-public

Adds get and set functions for all private properties.
TypeScript
1
star
34

etcd3-ts

Etcd client for node.js
TypeScript
1
star