Skip to content

Commit b8e5e06

Browse files
authored
Support for multiple distinct instances, as in Passport itself (#186)
1 parent 8e07bfb commit b8e5e06

File tree

4 files changed

+206
-191
lines changed

4 files changed

+206
-191
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@
33
All notable changes to this project will be documented in this file.
44
This project adheres to [Semantic Versioning](http://semver.org/).
55

6+
## Unreleased
7+
8+
### Added
9+
10+
- Added a new named export `AuthTokenRefresh`. This is a
11+
constructor that can be invoked to create a distinct instance, for
12+
applications that require more than one Passport instance.
13+
614
## [2.1.0] - 2021-06-29
715

816
### Added

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,23 @@ const extraParams = { some: 'extra_param' };
113113
refresh.requestNewAccessToken('gmail', 'some_refresh_token', extraParams, done);
114114
```
115115

116+
### Multiple instances
117+
118+
Projects that need multiple instances of Passport can construct them using the `Passport`
119+
constructor available on the `passport` module. Similarly, this module provides
120+
an `AuthTokenRefresh` constructor that can be used instead of the single instance provided
121+
by default.
122+
123+
```javascript
124+
const { Passport } = require('passport');
125+
const { AuthTokenRefresh } = require('passport-oauth2-refresh');
126+
127+
const passport = new Passport();
128+
const refresh = new AuthTokenRefresh();
129+
130+
// Additional, distinct instances of these modules can also be created
131+
```
132+
116133
## Examples
117134

118135
- See [issue #1](https://github.com/fiznool/passport-oauth2-refresh/issues/1) for an example of how to refresh a token when requesting data from the Google APIs.

lib/refresh.js

Lines changed: 131 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,142 @@
11
'use strict';
22

3-
const AuthTokenRefresh = {};
4-
5-
AuthTokenRefresh._strategies = {};
6-
7-
/**
8-
* Register a passport strategy so it can refresh an access token,
9-
* with optional `name`, overridding the strategy's default name.
10-
*
11-
* A third optional options parameter is available, which can be
12-
* used to create a custom OAuth2 adapter, or modify the one
13-
* which is automatically created. This is useful if the
14-
* strategy does not expose its internal OAuth2 adapter, or
15-
* customizes the adapter in some way that needs to be replicated.
16-
*
17-
* Examples:
18-
*
19-
* refresh.use(strategy);
20-
* refresh.use('facebook', strategy);
21-
* refresh.use('activedirectory', strategy, {
22-
* setRefreshOAuth2() {
23-
* return new OAuth2(...);
24-
* }
25-
* });
26-
*
27-
* @param {String|Strategy} name
28-
* @param {Strategy} passport strategy
29-
* @param {Object} options
30-
* @param {OAuth2} options.setRefreshOAuth2 a callback to modify the oauth2 adapter. Should return the oauth2 adapter to use when refreshing the token.
31-
*/
32-
AuthTokenRefresh.use = function (name, strategy, options) {
33-
if (typeof name !== 'string') {
34-
// Infer name from strategy
35-
options = strategy;
36-
strategy = name;
37-
name = strategy && strategy.name;
3+
class AuthTokenRefresh {
4+
constructor() {
5+
this._strategies = {};
386
}
39-
40-
if (strategy == null) {
41-
throw new Error('Cannot register: strategy is null');
42-
}
43-
44-
if (!name) {
45-
throw new Error(
46-
'Cannot register: name must be specified, or strategy must include name',
47-
);
48-
}
49-
50-
options = options || {};
51-
52-
let refreshOAuth2 = undefined;
53-
54-
if (strategy._oauth2) {
55-
// Try to use the internal oauth2 adapter, setting some sane defaults.
56-
// Use the strategy's OAuth2 object, since it might have been overwritten.
57-
// https://github.com/fiznool/passport-oauth2-refresh/issues/3
58-
const OAuth2 = strategy._oauth2.constructor;
59-
60-
// Generate our own oauth2 object for use later.
61-
// Use the strategy's _refreshURL, if defined,
62-
// otherwise use the regular accessTokenUrl.
63-
refreshOAuth2 = new OAuth2(
64-
strategy._oauth2._clientId,
65-
strategy._oauth2._clientSecret,
66-
strategy._oauth2._baseSite,
67-
strategy._oauth2._authorizeUrl,
68-
strategy._refreshURL || strategy._oauth2._accessTokenUrl,
69-
strategy._oauth2._customHeaders,
70-
);
71-
72-
// Some strategies overwrite the getOAuthAccessToken function to set headers
73-
// https://github.com/fiznool/passport-oauth2-refresh/issues/10
74-
refreshOAuth2.getOAuthAccessToken = strategy._oauth2.getOAuthAccessToken;
75-
}
76-
77-
// See if we need to customise the OAuth2 object any further
78-
if (typeof options.setRefreshOAuth2 === 'function') {
79-
refreshOAuth2 = options.setRefreshOAuth2({
80-
strategyOAuth2: strategy._oauth2,
7+
/**
8+
* Register a passport strategy so it can refresh an access token,
9+
* with optional `name`, overridding the strategy's default name.
10+
*
11+
* A third optional options parameter is available, which can be
12+
* used to create a custom OAuth2 adapter, or modify the one
13+
* which is automatically created. This is useful if the
14+
* strategy does not expose its internal OAuth2 adapter, or
15+
* customizes the adapter in some way that needs to be replicated.
16+
*
17+
* Examples:
18+
*
19+
* refresh.use(strategy);
20+
* refresh.use('facebook', strategy);
21+
* refresh.use('activedirectory', strategy, {
22+
* setRefreshOAuth2() {
23+
* return new OAuth2(...);
24+
* }
25+
* });
26+
*
27+
* @param {String|Strategy} name
28+
* @param {Strategy} passport strategy
29+
* @param {Object} options
30+
* @param {OAuth2} options.setRefreshOAuth2 a callback to modify the oauth2 adapter. Should return the oauth2 adapter to use when refreshing the token.
31+
*/
32+
use(name, strategy, options) {
33+
if (typeof name !== 'string') {
34+
// Infer name from strategy
35+
options = strategy;
36+
strategy = name;
37+
name = strategy && strategy.name;
38+
}
39+
40+
if (strategy == null) {
41+
throw new Error('Cannot register: strategy is null');
42+
}
43+
44+
if (!name) {
45+
throw new Error(
46+
'Cannot register: name must be specified, or strategy must include name',
47+
);
48+
}
49+
50+
options = options || {};
51+
52+
let refreshOAuth2 = undefined;
53+
54+
if (strategy._oauth2) {
55+
// Try to use the internal oauth2 adapter, setting some sane defaults.
56+
// Use the strategy's OAuth2 object, since it might have been overwritten.
57+
// https://github.com/fiznool/passport-oauth2-refresh/issues/3
58+
const OAuth2 = strategy._oauth2.constructor;
59+
60+
// Generate our own oauth2 object for use later.
61+
// Use the strategy's _refreshURL, if defined,
62+
// otherwise use the regular accessTokenUrl.
63+
refreshOAuth2 = new OAuth2(
64+
strategy._oauth2._clientId,
65+
strategy._oauth2._clientSecret,
66+
strategy._oauth2._baseSite,
67+
strategy._oauth2._authorizeUrl,
68+
strategy._refreshURL || strategy._oauth2._accessTokenUrl,
69+
strategy._oauth2._customHeaders,
70+
);
71+
72+
// Some strategies overwrite the getOAuthAccessToken function to set headers
73+
// https://github.com/fiznool/passport-oauth2-refresh/issues/10
74+
refreshOAuth2.getOAuthAccessToken = strategy._oauth2.getOAuthAccessToken;
75+
}
76+
77+
// See if we need to customise the OAuth2 object any further
78+
if (typeof options.setRefreshOAuth2 === 'function') {
79+
refreshOAuth2 = options.setRefreshOAuth2({
80+
strategyOAuth2: strategy._oauth2,
81+
refreshOAuth2,
82+
});
83+
}
84+
85+
if (!refreshOAuth2) {
86+
throw new Error(
87+
'The OAuth2 adapter used to refresh the token is not configured correctly. Use the setRefreshOAuth2 option to return a OAuth 2.0 adapter.',
88+
);
89+
}
90+
91+
// Set the strategy and oauth2 adapter for use later
92+
this._strategies[name] = {
93+
strategy,
8194
refreshOAuth2,
82-
});
95+
};
8396
}
8497

85-
if (!refreshOAuth2) {
86-
throw new Error(
87-
'The OAuth2 adapter used to refresh the token is not configured correctly. Use the setRefreshOAuth2 option to return a OAuth 2.0 adapter.',
88-
);
98+
/**
99+
* Check if a strategy is registered for refreshing.
100+
* @param {String} name Strategy name
101+
* @return {Boolean}
102+
*/
103+
has(name) {
104+
return !!this._strategies[name];
89105
}
90106

91-
// Set the strategy and oauth2 adapter for use later
92-
AuthTokenRefresh._strategies[name] = {
93-
strategy,
94-
refreshOAuth2,
95-
};
96-
};
97-
98-
/**
99-
* Check if a strategy is registered for refreshing.
100-
* @param {String} name Strategy name
101-
* @return {Boolean}
102-
*/
103-
AuthTokenRefresh.has = function (name) {
104-
return !!AuthTokenRefresh._strategies[name];
105-
};
106-
107-
/**
108-
* Request a new access token, using the passed refreshToken,
109-
* for the given strategy.
110-
* @param {String} name Strategy name. Must have already
111-
* been registered.
112-
* @param {String} refreshToken Refresh token to be sent to request
113-
* a new access token.
114-
* @param {Object} params (optional) an object containing additional
115-
* params to use when requesting the token.
116-
* @param {Function} done Callback when all is done.
117-
*/
118-
AuthTokenRefresh.requestNewAccessToken = function (
119-
name,
120-
refreshToken,
121-
params,
122-
done,
123-
) {
124-
if (arguments.length === 3) {
125-
done = params;
126-
params = {};
107+
/**
108+
* Request a new access token, using the passed refreshToken,
109+
* for the given strategy.
110+
* @param {String} name Strategy name. Must have already
111+
* been registered.
112+
* @param {String} refreshToken Refresh token to be sent to request
113+
* a new access token.
114+
* @param {Object} params (optional) an object containing additional
115+
* params to use when requesting the token.
116+
* @param {Function} done Callback when all is done.
117+
*/
118+
requestNewAccessToken(name, refreshToken, params, done) {
119+
if (arguments.length === 3) {
120+
done = params;
121+
params = {};
122+
}
123+
124+
// Send a request to refresh an access token, and call the passed
125+
// callback with the result.
126+
const strategy = this._strategies[name];
127+
if (!strategy) {
128+
return done(new Error('Strategy was not registered to refresh a token'));
129+
}
130+
131+
params = params || {};
132+
params.grant_type = 'refresh_token';
133+
134+
strategy.refreshOAuth2.getOAuthAccessToken(refreshToken, params, done);
127135
}
136+
}
128137

129-
// Send a request to refresh an access token, and call the passed
130-
// callback with the result.
131-
const strategy = AuthTokenRefresh._strategies[name];
132-
if (!strategy) {
133-
return done(new Error('Strategy was not registered to refresh a token'));
134-
}
135-
136-
params = params || {};
137-
params.grant_type = 'refresh_token';
138-
139-
strategy.refreshOAuth2.getOAuthAccessToken(refreshToken, params, done);
140-
};
138+
// Default export, for typical case & backwards compatibility
139+
module.exports = new AuthTokenRefresh();
141140

142-
module.exports = AuthTokenRefresh;
141+
// Export a constructor, just like Passport does
142+
module.exports.AuthTokenRefresh = AuthTokenRefresh;

0 commit comments

Comments
 (0)