express-authenticators
Advanced tools
Comparing version 0.0.7 to 0.0.8
@@ -104,3 +104,3 @@ "use strict"; | ||
switch (_b.label) { | ||
case 0: return [4 /*yield*/, node_fetch_1.default("https://graph.facebook.com/v6.0/me?" + qs.stringify({ | ||
case 0: return [4 /*yield*/, node_fetch_1.default("https://graph.facebook.com/v9.0/me?" + qs.stringify({ | ||
access_token: token, | ||
@@ -126,3 +126,3 @@ fields: fields.join(',') | ||
emailVerified: !!profile.email, | ||
avatar: "https://graph.facebook.com/v6.0/" + profile.id + "/picture?width=" + profilePictureWidth, | ||
avatar: "https://graph.facebook.com/v9.0/" + profile.id + "/picture?width=" + profilePictureWidth, | ||
raw: profile | ||
@@ -137,6 +137,7 @@ }]; | ||
function FacebookAuthenticator(options) { | ||
var _this = _super.call(this, __assign({ consentURL: 'https://www.facebook.com/v6.0/dialog/oauth', tokenURL: 'https://graph.facebook.com/v6.0/oauth/access_token', scope: ['email'].join(',') }, options), { | ||
var _this = _super.call(this, __assign({ consentURL: 'https://www.facebook.com/v9.0/dialog/oauth', tokenURL: 'https://graph.facebook.com/v9.0/oauth/access_token', scope: ['email'].join(',') }, options), { | ||
ignoreGrantType: true, | ||
tokenRequestMethod: OAuth2_1.TokenRequestMethod.GET, | ||
includeStateInAccessToken: false | ||
includeStateInAccessToken: false, | ||
enablePKCE: true, | ||
}) || this; | ||
@@ -143,0 +144,0 @@ _this.fetchProfile = fetchFacebookProfile; |
@@ -128,3 +128,4 @@ "use strict"; | ||
tokenRequestMethod: OAuth2_1.TokenRequestMethod.GET, | ||
includeStateInAccessToken: false | ||
includeStateInAccessToken: false, | ||
enablePKCE: true, | ||
}) || this; | ||
@@ -131,0 +132,0 @@ _this.fetchProfile = fetchFoursquareProfile; |
@@ -156,3 +156,4 @@ "use strict"; | ||
tokenRequestMethod: OAuth2_1.TokenRequestMethod.POST, | ||
includeStateInAccessToken: true | ||
includeStateInAccessToken: true, | ||
enablePKCE: true, | ||
}) || this; | ||
@@ -159,0 +160,0 @@ _this.fetchProfile = exports.fetchGithubProfile; |
import OAuth2 from './oauth2/OAuth2'; | ||
import { IOAuthProfileFetcher } from './OAuthCommon'; | ||
export default class GoogleAuthenticator extends OAuth2 implements IOAuthProfileFetcher<string> { | ||
private childConfig; | ||
fetchProfile: (token: string, fields?: string[]) => Promise<{ | ||
@@ -43,3 +44,3 @@ raw: any; | ||
}>; | ||
constructor(options: { | ||
constructor(childConfig: { | ||
clientID: string; | ||
@@ -50,2 +51,3 @@ clientSecret: string; | ||
}); | ||
refreshAccessToken(refreshToken: string): Promise<any>; | ||
} |
@@ -86,3 +86,3 @@ "use strict"; | ||
var OAuth2_1 = __importStar(require("./oauth2/OAuth2")); | ||
var qs = __importStar(require("qs")); | ||
var qs_1 = __importDefault(require("qs")); | ||
var node_fetch_1 = __importDefault(require("node-fetch")); | ||
@@ -104,3 +104,3 @@ var OAuthCommon_1 = require("./OAuthCommon"); | ||
switch (_c.label) { | ||
case 0: return [4 /*yield*/, node_fetch_1.default("https://people.googleapis.com/v1/people/me?" + qs.stringify({ | ||
case 0: return [4 /*yield*/, node_fetch_1.default("https://people.googleapis.com/v1/people/me?" + qs_1.default.stringify({ | ||
access_token: token, | ||
@@ -186,16 +186,44 @@ personFields: fields.join(',') | ||
__extends(GoogleAuthenticator, _super); | ||
function GoogleAuthenticator(options) { | ||
function GoogleAuthenticator(childConfig) { | ||
var _this = _super.call(this, __assign({ consentURL: 'https://accounts.google.com/o/oauth2/v2/auth', tokenURL: 'https://oauth2.googleapis.com/token', scope: [ | ||
'https://www.googleapis.com/auth/userinfo.email', | ||
'https://www.googleapis.com/auth/userinfo.profile' | ||
].join(' ') }, options), { | ||
].join(' ') }, childConfig), { | ||
ignoreGrantType: false, | ||
tokenRequestMethod: OAuth2_1.TokenRequestMethod.POST, | ||
includeStateInAccessToken: false | ||
includeStateInAccessToken: false, | ||
enablePKCE: true, | ||
}) || this; | ||
_this.childConfig = childConfig; | ||
_this.fetchProfile = fetchGoogleProfile; | ||
return _this; | ||
} | ||
GoogleAuthenticator.prototype.refreshAccessToken = function (refreshToken) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var response; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, node_fetch_1.default('https://oauth2.googleapis.com/token', { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/x-www-form-urlencoded', | ||
Accept: 'application/json', | ||
}, | ||
body: qs_1.default.stringify({ | ||
client_id: this.childConfig.clientID, | ||
client_secret: this.childConfig.clientSecret, | ||
grant_type: 'refresh_token', | ||
refresh_token: refreshToken | ||
}) | ||
})]; | ||
case 1: | ||
response = _a.sent(); | ||
return [4 /*yield*/, response.json()]; | ||
case 2: return [2 /*return*/, _a.sent()]; | ||
} | ||
}); | ||
}); | ||
}; | ||
return GoogleAuthenticator; | ||
}(OAuth2_1.default)); | ||
exports.default = GoogleAuthenticator; |
@@ -146,7 +146,9 @@ "use strict"; | ||
var _this = _super.call(this, __assign({ consentURL: 'https://api.instagram.com/oauth/authorize', tokenURL: 'https://api.instagram.com/oauth/access_token', scope: [ | ||
'user_profile', | ||
'instagram_graph_user_profile', | ||
'instagram_graph_user_media' | ||
].join(' ') }, options), { | ||
ignoreGrantType: false, | ||
tokenRequestMethod: OAuth2_1.TokenRequestMethod.POST, | ||
includeStateInAccessToken: false | ||
includeStateInAccessToken: false, | ||
enablePKCE: true, | ||
}) || this; | ||
@@ -153,0 +155,0 @@ _this.fetchProfile = fetchInstagramProfile; |
@@ -135,3 +135,4 @@ "use strict"; | ||
tokenRequestMethod: OAuth2_1.TokenRequestMethod.POST, | ||
includeStateInAccessToken: true | ||
includeStateInAccessToken: true, | ||
enablePKCE: true, | ||
}) || this; | ||
@@ -138,0 +139,0 @@ _this.fetchProfile = fetchLinkedInProfile; |
@@ -21,2 +21,3 @@ import { Request, Response } from 'express'; | ||
includeStateInAccessToken: boolean; | ||
enablePKCE: boolean; | ||
}); | ||
@@ -23,0 +24,0 @@ callback(req: Request): Promise<any>; |
@@ -77,2 +77,3 @@ "use strict"; | ||
var OAuth2Error_1 = __importDefault(require("./OAuth2Error")); | ||
var crypto_1 = __importDefault(require("crypto")); | ||
var sessionKey = 'oauth2'; | ||
@@ -91,10 +92,9 @@ var TokenRequestMethod; | ||
OAuth2.prototype.callback = function (req) { | ||
var _a, _b; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var sessionState, state, error, code, requestBody, response, _c, _d, json, err_1, access_token, token_type, expires_in; | ||
return __generator(this, function (_e) { | ||
switch (_e.label) { | ||
var _a, sessionState, verifier, state, error, code, body, response, _b, _c, json, err_1; | ||
return __generator(this, function (_d) { | ||
switch (_d.label) { | ||
case 0: | ||
sessionState = (_a = req.session[sessionKey]) === null || _a === void 0 ? void 0 : _a.state; | ||
(_b = req.session[sessionKey]) === null || _b === void 0 ? true : delete _b.state; | ||
_a = req.session[sessionKey] || {}, sessionState = _a.state, verifier = _a.verifier; | ||
delete req.session[sessionKey]; | ||
state = req.query.state; | ||
@@ -117,7 +117,7 @@ if (state !== sessionState) | ||
code = req.query.code; | ||
requestBody = __assign(__assign({ client_id: this.config.clientID, redirect_uri: this.config.redirectUri, client_secret: this.config.clientSecret, code: code }, !this.options.ignoreGrantType && { grant_type: 'authorization_code' }), this.options.includeStateInAccessToken && { state: state }); | ||
body = qs.stringify(__assign(__assign(__assign({ client_id: this.config.clientID, redirect_uri: this.config.redirectUri, client_secret: this.config.clientSecret, code: code }, !this.options.ignoreGrantType && { grant_type: 'authorization_code' }), this.options.includeStateInAccessToken && { state: state }), this.options.enablePKCE && { code_verifier: verifier })); | ||
if (!(this.options.tokenRequestMethod === TokenRequestMethod.GET)) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, node_fetch_1.default(this.config.tokenURL + "?" + qs.stringify(requestBody))]; | ||
return [4 /*yield*/, node_fetch_1.default(this.config.tokenURL + "?" + body)]; | ||
case 1: | ||
_c = _e.sent(); | ||
_b = _d.sent(); | ||
return [3 /*break*/, 4]; | ||
@@ -130,27 +130,27 @@ case 2: return [4 /*yield*/, node_fetch_1.default(this.config.tokenURL, { | ||
}, | ||
body: qs.stringify(requestBody) | ||
body: body | ||
})]; | ||
case 3: | ||
_c = _e.sent(); | ||
_e.label = 4; | ||
_b = _d.sent(); | ||
_d.label = 4; | ||
case 4: | ||
response = _c; | ||
response = _b; | ||
if (!!response.ok) return [3 /*break*/, 6]; | ||
_d = OAuth2Error_1.default.bind; | ||
_c = OAuth2Error_1.default.bind; | ||
return [4 /*yield*/, response.text()]; | ||
case 5: throw new (_d.apply(OAuth2Error_1.default, [void 0, (_e.sent()) || 'Cannot get access token']))(); | ||
case 5: throw new (_c.apply(OAuth2Error_1.default, [void 0, (_d.sent()) || 'Cannot get access token']))(); | ||
case 6: | ||
_e.trys.push([6, 8, , 9]); | ||
_d.trys.push([6, 8, , 9]); | ||
return [4 /*yield*/, response.json()]; | ||
case 7: | ||
json = _e.sent(); | ||
json = _d.sent(); | ||
return [3 /*break*/, 9]; | ||
case 8: | ||
err_1 = _e.sent(); | ||
err_1 = _d.sent(); | ||
throw new OAuth2Error_1.default(err_1.message); | ||
case 9: | ||
access_token = json.access_token, token_type = json.token_type, expires_in = json.expires_in; | ||
if (!access_token) | ||
// const {access_token, token_type, expires_in, refresh_token} = json | ||
if (!json.access_token) | ||
throw new OAuth2Error_1.default('Token not found'); | ||
return [2 /*return*/, access_token]; | ||
return [2 /*return*/, json]; | ||
} | ||
@@ -162,10 +162,15 @@ }); | ||
var state = uuid_1.v4(); | ||
req.session[sessionKey] = { state: state }; | ||
res.status(302).redirect(this.config.consentURL + "?" + qs.stringify({ | ||
client_id: this.config.clientID, | ||
redirect_uri: this.config.redirectUri, | ||
state: state, | ||
scope: this.config.scope, | ||
response_type: 'code' | ||
})); | ||
var verifier = uuid_1.v4(); | ||
req.session[sessionKey] = { state: state, verifier: verifier }; | ||
res.status(302).redirect(this.config.consentURL + "?" + qs.stringify(__assign({ client_id: this.config.clientID, redirect_uri: this.config.redirectUri, state: state, scope: this.config.scope, response_type: 'code' }, this.options.enablePKCE && { | ||
code_challenge: crypto_1.default | ||
.createHash('sha256') | ||
.update(Buffer.from(verifier)) | ||
.digest() | ||
.toString('base64') | ||
.replace(/\+/g, '-') | ||
.replace(/\//g, '_') | ||
.replace(/=/g, ''), | ||
code_challenge_method: 'S256' | ||
}))); | ||
}; | ||
@@ -172,0 +177,0 @@ return OAuth2; |
@@ -120,3 +120,4 @@ "use strict"; | ||
tokenRequestMethod: OAuth2_1.TokenRequestMethod.POST, | ||
includeStateInAccessToken: false | ||
includeStateInAccessToken: false, | ||
enablePKCE: true, | ||
}) || this; | ||
@@ -123,0 +124,0 @@ _this.fetchProfile = fetchPinterestProfile; |
{ | ||
"name": "express-authenticators", | ||
"version": "0.0.7", | ||
"version": "0.0.8", | ||
"description": "Third party authenticators in nodejs. Support various providers. Zero heavy dependencies.", | ||
@@ -38,35 +38,35 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"middleware-async": "^1.2.7", | ||
"node-fetch": "^2.6.0", | ||
"middleware-async": "^1.3.1", | ||
"node-fetch": "^2.6.1", | ||
"qs": "^6.9.4", | ||
"r3986": "^0.0.3", | ||
"uuid": "^8.3.0" | ||
"uuid": "^8.3.2" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "^7.11.4", | ||
"@babel/plugin-proposal-class-properties": "^7.10.4", | ||
"@babel/core": "^7.12.10", | ||
"@babel/plugin-proposal-class-properties": "^7.12.1", | ||
"@babel/plugin-syntax-object-rest-spread": "^7.8.3", | ||
"@babel/plugin-transform-runtime": "^7.11.0", | ||
"@babel/preset-env": "^7.11.0", | ||
"@babel/preset-typescript": "^7.10.4", | ||
"@babel/runtime": "^7.11.2", | ||
"@types/express": "^4.17.7", | ||
"@types/express-session": "^1.17.0", | ||
"@types/jest": "^26.0.10", | ||
"@types/node": "^14.6.0", | ||
"@babel/plugin-transform-runtime": "^7.12.10", | ||
"@babel/preset-env": "^7.12.10", | ||
"@babel/preset-typescript": "^7.12.7", | ||
"@babel/runtime": "^7.12.5", | ||
"@types/express": "^4.17.9", | ||
"@types/express-session": "^1.17.3", | ||
"@types/jest": "^26.0.19", | ||
"@types/node": "^14.14.13", | ||
"@types/node-fetch": "^2.5.7", | ||
"@types/uuid": "^8.3.0", | ||
"@typescript-eslint/eslint-plugin": "^3.9.1", | ||
"@typescript-eslint/parser": "^3.9.1", | ||
"@typescript-eslint/eslint-plugin": "^4.9.1", | ||
"@typescript-eslint/parser": "^4.9.1", | ||
"babel-eslint": "^10.1.0", | ||
"babel-jest": "^26.3.0", | ||
"eslint": "^7.7.0", | ||
"eslint-config-airbnb-base": "^14.2.0", | ||
"babel-jest": "^26.6.3", | ||
"eslint": "^7.15.0", | ||
"eslint-config-airbnb-base": "^14.2.1", | ||
"eslint-plugin-babel": "^5.3.1", | ||
"eslint-plugin-import": "^2.22.0", | ||
"eslint-plugin-jest": "^23.20.0", | ||
"jest": "^26.4.1", | ||
"eslint-plugin-import": "^2.22.1", | ||
"eslint-plugin-jest": "^24.1.3", | ||
"jest": "^26.6.3", | ||
"tslint": "^6.1.3", | ||
"typescript": "^4.0.2" | ||
"typescript": "^4.1.3" | ||
} | ||
} |
@@ -9,2 +9,3 @@ # Express Authenticators [![Build Status](https://travis-ci.org/tranvansang/express-authenticators.svg?branch=master)](https://travis-ci.org/tranvansang/express-authenticators) | ||
- Support fetching user profile for various providers: Google, Facebook, Twitter, Instagram, Tumblr, Github, LinkedIn, Pinterest, Foursquare. | ||
- Support PKCE([Proof Key for Code Exchange](https://oauth.net/2/pkce/)). | ||
@@ -35,3 +36,3 @@ # Usage | ||
const session = require('express-session') | ||
const asyncMiddleware = require('middleware-async') | ||
const asyncMiddleware = require('middleware-async').default | ||
@@ -50,3 +51,3 @@ const app = express() | ||
(req, res, next) => { | ||
req.session!.someInfo = 'my info' // store the user credential | ||
req.session.someInfo = 'my info' // store the user credential | ||
facebookAuth.authenticate(req, res, next) | ||
@@ -81,3 +82,3 @@ } | ||
```typescript | ||
constructor(option: { | ||
constructor(option: { | ||
clientID: 'app id', | ||
@@ -84,0 +85,0 @@ clientSecret: 'app secret', |
115410
2155
185
Updatedmiddleware-async@^1.3.1
Updatednode-fetch@^2.6.1
Updateduuid@^8.3.2