Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/jwalton/passport-api-docs

Documentation for Passport.js.
https://github.com/jwalton/passport-api-docs

Last synced: about 2 months ago
JSON representation

Documentation for Passport.js.

Awesome Lists containing this project

README

        

# Passport: The Hidden Manual

* [Russian Translation](https://github.com/jwalton/passport-api-docs/blob/master/README_RU.md) courtesy of [@kirillurgant](https://github.com/kirillurgant)

## Table of Contents

* [Intro](#intro)
* [Passport class](#passport-class)
* [passport.initialize()](#passportinitialize)
* [passport.session(options)](#passportsessionoptions)
* [passport.authenticate(strategyName, options, callback)](#passportauthenticatestrategyname-options-callback)
* [passport.authorize(strategyName, options, callback)](#passportauthorizestrategyname-options-callback)
* [passport.use(strategyName, strategy)](#passportusestrategyname-strategy)
* [passport.serializeUser(fn(user, done) | fn(req, user, done))](#passportserializeuserfnuser-done--fnreq-user-done)
* [passport.deserializeUser(fn(serializedUser, done) | fn(req, serializedUser, done))](#passportdeserializeuserfnserializeduser-done--fnreq-serializeduser-done)
* [Strategies](#strategies)
* [Writing custom strategies](#writing-custom-strategies)
* [Verify Callback](#verify-callback)
* [Functions added to the Request](#functions-added-to-the-request)
* [req.login(user, callback)](#reqloginuser-callback)
* [req.logout()](#reqlogout)
* [Passport and Sessions](#passport-and-sessions)

## Intro

The official [passport documentation](http://www.passportjs.org/docs/) 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:

```js
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:

```js
app.use(passport.session());
```

is actually the same as:

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

which is using the [built-in "session strategy"](https://github.com/jaredhanson/passport/blob/2327a36e7c005ccc7134ad157b2f258b57aa0912/lib/strategies/session.js). 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](https://github.com/jaredhanson/passport-oauth1/blob/4f8e3404126ef56b3e564e1e1702f5ede1e9a661/lib/strategy.js#L232).

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()`:

```js
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](https://github.com/mozilla/node-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](https://github.com/jaredhanson/passport-strategy). You can unit test a strategy in isolation with [passport-strategy-runner](https://github.com/jwalton/passport-strategy-runner).

```js
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](https://tools.ietf.org/html/rfc7235#section-2.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](https://github.com/jaredhanson/passport/blob/2327a36e7c005ccc7134ad157b2f258b57aa0912/lib/strategies/session.js) - 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](https://github.com/jaredhanson/passport/blob/2327a36e7c005ccc7134ad157b2f258b57aa0912/lib/sessionmanager.js#L12-L28), and essentially does:

```js
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.