├── .gitignore ├── lib └── passport-azure-ad-oauth2 │ ├── index.js │ └── strategy.js ├── test ├── module.test.js └── strategy.test.js ├── LICENSE ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | -------------------------------------------------------------------------------- /lib/passport-azure-ad-oauth2/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module dependencies. 3 | */ 4 | var Strategy = require('./strategy'); 5 | 6 | 7 | /** 8 | * Expose `Strategy` directly from package. 9 | */ 10 | exports = module.exports = Strategy; 11 | 12 | /** 13 | * Export constructors. 14 | */ 15 | exports.Strategy = Strategy; 16 | -------------------------------------------------------------------------------- /test/module.test.js: -------------------------------------------------------------------------------- 1 | var strategy = require('..'); 2 | var expect = require('chai').expect; 3 | 4 | describe('passport-azure-ad-oauth2', function () { 5 | 6 | it('should export Strategy constructor directly from package', function () { 7 | expect(strategy).to.be.a('function'); 8 | expect(strategy).to.equal(strategy.Strategy); 9 | }); 10 | 11 | it('should export Strategy constructor', function () { 12 | expect(strategy.Strategy).to.be.a('function'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /test/strategy.test.js: -------------------------------------------------------------------------------- 1 | var expect = require('chai').expect; 2 | var AzureAdOAuth2Strategy = require('..'); 3 | 4 | describe('Strategy', function() { 5 | 6 | var strategy = new AzureAdOAuth2Strategy({ 7 | clientID: 'abc123', 8 | clientSecret: 'shhh', 9 | callbackURL: 'https://www.example.net/auth/azureadoauth2/callback', 10 | resource: '00000002-0000-0000-c000-000000000000', 11 | tenant: 'contoso.onmicrosoft.com' 12 | }, 13 | function () {}); 14 | 15 | it('should be named azure_ad_oauth2', function () { 16 | expect(strategy.name).to.equal('azure_ad_oauth2'); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2014 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "passport-azure-ad-oauth2", 3 | "version": "0.0.3", 4 | "description": "Passport strategy for authenticating with Azure AD using the OAuth 2.0 protocol.", 5 | "keywords": [ 6 | "passport", 7 | "waad", 8 | "oauth", 9 | "azure active directory", 10 | "azure ad", 11 | "auth", 12 | "authn", 13 | "authentication", 14 | "identity" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git://github.com/auth0/passport-azure-ad-oauth2.git" 19 | }, 20 | "bugs": { 21 | "url": "http://github.com/auth0/passport-azure-ad-oauth2/issues" 22 | }, 23 | "author": { 24 | "name": "Auth0", 25 | "email": "support@auth0.com", 26 | "url": "http://www.auth0.com/" 27 | }, 28 | "licenses": [ 29 | { 30 | "type": "MIT", 31 | "url": "http://www.opensource.org/licenses/MIT" 32 | } 33 | ], 34 | "main": "./lib/passport-azure-ad-oauth2", 35 | "dependencies": { 36 | "passport-oauth": "1.0.x" 37 | }, 38 | "devDependencies": { 39 | "mocha": "1.x.x", 40 | "chai": "1.x.x" 41 | }, 42 | "scripts": { 43 | "test": "node_modules/.bin/mocha --reporter spec test/*.test.js" 44 | }, 45 | "homepage": "https://github.com/auth0/passport-azure-ad-oauth2" 46 | } 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Passport-azure-ad-oauth2 2 | 3 | [Passport](http://passportjs.org/) strategy for authenticating with [Azure AD](http://msdn.microsoft.com/en-us/library/azure/dn645545.aspx) 4 | using the OAuth 2.0 protocol. 5 | 6 | ## Install 7 | 8 | $ npm install passport-azure-ad-oauth2 9 | 10 | ## Usage 11 | 12 | #### Configure Strategy 13 | 14 | The Azure AD OAuth 2.0 authentication strategy authenticates requests by delegating to Azure AD using the OAuth 2.0 protocol. 15 | 16 | Applications must supply a `verify` callback which accepts an `accessToken`, `refresh_token`, `params` 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. 17 | 18 | ##### Options 19 | 20 | * `clientID`: specifies the client id of the application that is registered in Azure Active Directory. 21 | * `clientSecret`: secret used to establish ownership of the client Id. 22 | * `callbackURL`: URL to which Azure AD will redirect the user after obtaining authorization. 23 | * `resource`: [optional] the App ID URI of the web API (secured resource). 24 | * `tenant`: [optional] tenant domain (e.g.: contoso.onmicrosoft.com). 25 | 26 | ```javascript 27 | passport.use(new AzureAdOAuth2Strategy({ 28 | clientID: '{YOUR_CLIENT_ID}', 29 | clientSecret: '{YOUR_CLIENT_SECRET}', 30 | callbackURL: 'https://www.example.net/auth/azureadoauth2/callback', 31 | resource: '00000002-0000-0000-c000-000000000000', 32 | tenant: 'contoso.onmicrosoft.com' 33 | }, 34 | function (accessToken, refresh_token, params, profile, done) { 35 | var waadProfile = profile || jwt.decode(params.id_token, '', true); 36 | 37 | User.findOrCreate({ id: waadProfile.upn }, function (err, user) { 38 | done(err, user); 39 | }); 40 | })); 41 | ``` 42 | 43 | #### Authenticate Requests 44 | 45 | Use `passport.authenticate()`, specifying the `'azure_ad_oauth2'` strategy, to authenticate requests. 46 | 47 | For example, as route middleware in an [Express](http://expressjs.com/) application: 48 | 49 | ```javascript 50 | app.get('/auth/azureadoauth2', 51 | passport.authenticate('azure_ad_oauth2')); 52 | 53 | app.get('/auth/azureadoauth2/callback', 54 | passport.authenticate('azure_ad_oauth2', { failureRedirect: '/login' }), 55 | function (req, res) { 56 | // Successful authentication, redirect home. 57 | res.redirect('/'); 58 | }); 59 | ``` 60 | 61 | ## Tests 62 | 63 | $ npm install 64 | $ npm test 65 | 66 | ## Credits 67 | 68 | - [Jared Hanson](http://github.com/jaredhanson) 69 | - [Azure AD Team](https://github.com/AzureAD/azure-activedirectory-library-for-nodejs) 70 | 71 | ## License 72 | 73 | [The MIT License](http://opensource.org/licenses/MIT) 74 | -------------------------------------------------------------------------------- /lib/passport-azure-ad-oauth2/strategy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module dependencies. 3 | */ 4 | var util = require('util') 5 | , OAuth2Strategy = require('passport-oauth').OAuth2Strategy 6 | , InternalOAuthError = require('passport-oauth').InternalOAuthError; 7 | 8 | 9 | /** 10 | * `Strategy` constructor. 11 | * 12 | * The Azure AD OAuth 2.0 authentication strategy authenticates requests by delegating to 13 | * Azure AD using the OAuth 2.0 protocol. 14 | * 15 | * Applications must supply a `verify` callback which accepts an `accessToken`, 16 | * `refresh_token`, `params` and service-specific `profile`, and then calls the `done` 17 | * callback supplying a `user`, which should be set to `false` if the 18 | * credentials are not valid. If an exception occured, `err` should be set. 19 | * 20 | * Options: 21 | * - `clientID` specifies the client id of the application that is registered in Azure Active Directory 22 | * - `clientSecret` secret used to establish ownership of the client Id 23 | * - `callbackURL` URL to which Azure AD will redirect the user after obtaining authorization 24 | * - `resource` [optional] the App ID URI of the web API (secured resource) 25 | * - `tenant` [optional] tenant domain (e.g.: contoso.onmicrosoft.com) 26 | * 27 | * Examples: 28 | * 29 | * passport.use(new AzureAdOAuth2Strategy({ 30 | * clientID: 'yourClientId', 31 | * clientSecret: 'youAADIssuedClientSecret', 32 | * callbackURL: 'https://www.example.net/auth/azureadoauth2/callback', 33 | * resource: '00000002-0000-0000-c000-000000000000', 34 | * tenant: 'contoso.onmicrosoft.com' 35 | * }, 36 | * function (accessToken, refresh_token, params, profile, done) { 37 | * var waadProfile = profile || jwt.decode(params.id_token, '', true); 38 | * 39 | * User.findOrCreate({ id: waadProfile.upn }, function (err, user) { 40 | * done(err, user); 41 | * }); 42 | * } 43 | * )); 44 | * 45 | * @param {Object} options 46 | * @param {Function} verify 47 | * @api public 48 | */ 49 | function Strategy (options, verify) { 50 | // more details: http://msdn.microsoft.com/en-us/library/azure/dn645542.aspx 51 | options = options || {}; 52 | 53 | var base_url = 'https://login.windows.net/' + (options.tenant || 'common'); 54 | options.authorizationURL = options.authorizationURL || base_url + '/oauth2/authorize'; 55 | options.tokenURL = options.tokenURL || base_url + '/oauth2/token'; 56 | 57 | OAuth2Strategy.call(this, options, verify); 58 | 59 | this.name = 'azure_ad_oauth2'; 60 | this.resource = options.resource; 61 | } 62 | 63 | /** 64 | * Inherit from `OAuth2Strategy`. 65 | */ 66 | util.inherits(Strategy, OAuth2Strategy); 67 | 68 | /** 69 | * Authenticate request by delegating to Azure AD using OAuth. 70 | * 71 | * @param {Object} req 72 | * @api protected 73 | */ 74 | Strategy.prototype.authenticate = function (req, options) { 75 | if (!options.resource && this.resource) { // include default resource as authorization parameter 76 | options.resource = this.resource; 77 | } 78 | 79 | // Call the base class for standard OAuth authentication. 80 | OAuth2Strategy.prototype.authenticate.call(this, req, options); 81 | }; 82 | 83 | /** 84 | * Retrieve user profile from Azure AD. 85 | * 86 | * This function constructs a normalized profile, with the following properties: 87 | * 88 | * - `provider` always set to `azure_ad_oauth2` 89 | * - `id` 90 | * - `username` 91 | * - `displayName` 92 | * 93 | * @param {String} accessToken 94 | * @param {Function} done 95 | * @api protected 96 | */ 97 | Strategy.prototype.userProfile = function (accessToken, done) { 98 | done(null, { provider: 'azure_ad_oauth2' }); 99 | 100 | // TODO: Userinfo endpoint is not available yet 101 | /*this._oauth2.get('https://TODO', accessToken, function (err, body, res) { 102 | if (err) { return done(new InternalOAuthError('failed to fetch user profile', err)); } 103 | });*/ 104 | }; 105 | 106 | /** 107 | * Return extra Azure AD-specific parameters to be included in the authorization 108 | * request. 109 | * 110 | * @param {Object} options 111 | * @return {Object} 112 | * @api protected 113 | */ 114 | Strategy.prototype.authorizationParams = function (options) { 115 | return options; 116 | }; 117 | 118 | /** 119 | * Expose `Strategy`. 120 | */ 121 | module.exports = Strategy; 122 | --------------------------------------------------------------------------------