passport-exact
Version:
Exact authentication strategy for Passport.
124 lines (107 loc) • 3.94 kB
JavaScript
/**
* Module dependencies.
*/
var util = require('util')
,xml2js = require('xml2js').parseString
,OAuth2Strategy = require('passport-oauth').OAuth2Strategy
,InternalOAuthError = require('passport-oauth').InternalOAuthError;
/**
* `Strategy` constructor.
*
* The Exact authentication strategy authenticates requests by delegating to
* Exact using the OAuth 2.0 protocol.
*
* Applications must supply a `verify` callback which accepts an `accessToken`,
* `refreshToken` and service-specific `profile`, and then calls the `done`
* callback supplying a `user`, which should be set to `false` if the
* credentials are not valid. If an exception occured, `err` should be set.
*
* Options:
* - `clientID` your exact application's client id
* - `clientSecret` your exact application's client secret
* - `baseUrl` the base Url for the Exact servers. If not specified: https://start.exactonline.nl
* - `callbackURL` URL to which uber will redirect the user after granting authorization
*
* Examples:
*
* passport.use(new uberStrategy({
* clientID: '123-456-789',
* clientSecret: 'shhh-its-a-secret'
baseUrl: 'https://start.exactonline.nl'
* callbackURL: 'https://www.example.net/auth/exact/callback'
* },
* function(accessToken, refreshToken, profile, done) {
* User.findOrCreate(..., function (err, user) {
* done(err, user);
* });
* }
* ));
*
* @param {Object} options
* @param {Function} verify
* @api public
*/
function Strategy(options, verify) {
options = options || {};
options.baseUrl = options.baseUrl || 'https://start.exactonline.nl';
options.authorizationURL = options.baseUrl + '/api/oauth2/auth';
options.tokenURL = options.baseUrl + '/api/oauth2/token';
OAuth2Strategy.call(this, options, verify);
this.name = 'exact';
this.baseUrl = options.baseUrl;
}
/**
* Inherit from `OAuth2Strategy`.
*/
util.inherits(Strategy, OAuth2Strategy);
/**
* Retrieve user profile from Exact.
*
* This function constructs a normalized profile, with the following properties:
*
* - `provider` always set to `exact`
* - `id`
* - `displayName` FirstName + " " + LastName
*
* @param {String} accessToken
* @param {Function} done
* @api protected
*/
Strategy.prototype.userProfile = function(accessToken, done) {
this._oauth2._request('GET', this.baseUrl + '/api/v1/current/Me',
{Authorization: "Bearer " + accessToken },
null,
accessToken,
function (err, body, res) {
if (err) { return done(new InternalOAuthError('failed to fetch user profile', err)); }
try {
xml2js(body, { attrkey: 'A' }, function (e, json) {
if(e) return done(e);
var profile = { provider: 'exact' };
var properties = json.feed.entry[0].content[0]['m:properties'][0];
profile.id = properties['d:UserID'][0]['_'];
profile.displayName = properties['d:FullName'][0];
profile.firstName = properties['d:FirstName'][0];
profile.middleName = properties['d:MiddleName'][0];
profile.lastName = properties['d:LastName'][0];
profile.currentDivision = properties['d:CurrentDivision'][0]['_'];
profile.picture = properties['d:PictureUrl'][0];
profile.userName = properties['d:UserName'][0];
profile.languageCode = properties['d:LanguageCode'][0];
profile.email = properties['d:Email'][0];
profile.title = properties['d:Title'][0];
profile.gender = properties['d:Gender'][0];
profile.language = properties['d:Language'][0];
profile._json = json;
profile._xml = body;
done(null, profile);
});
} catch(e) {
done(e);
}
});
}
/**
* Expose `Strategy`.
*/
module.exports = Strategy;