UNPKG

37.6 kBMarkdownView Raw
1
2# Microsoft Azure Active Directory Passport.js Plug-In
3
4---
5
6_passport-azure-ad_ is a collection of [Passport](http://passportjs.org/) Strategies
7to help you integrate with Azure Active Directory. It includes OpenID Connect,
8WS-Federation, and SAML-P authentication and authorization. These providers let you
9integrate your Node app with Microsoft Azure AD so you can use its many features,
10including web single sign-on (WebSSO), Endpoint Protection with OAuth, and JWT token
11issuance and validation.
12
13_passport-azure-ad_ has been tested to work with both [Microsoft Azure Active Directory](https://azure.microsoft.com/en-us/services/active-directory/)
14and with [Microsoft Active Directory Federation Services](http://en.wikipedia.org/wiki/Active_Directory_Federation_Services).
15
16## 1. Security Vulnerability in Versions < 1.4.6 and 2.0.0
17_passport-azure-ad_ has a known security vulnerability affecting versions <1.4.6 and 2.0.0. Please update to >=1.4.6 or >=2.0.1 immediately. For more details, see the [security notice](https://github.com/AzureAD/passport-azure-ad/blob/master/SECURITY-NOTICE.MD).
18
19## 2. Versions
20Current version - 4.0.0
21Latest version that support's SAML and WSFED - 2.0.3
22Minimum recommended version - 1.4.6
23You can find the changes for each version in the [change log](https://github.com/AzureAD/passport-azure-ad/blob/master/CHANGELOG.md).
24
25## 3. Installation
26
27 $ npm install passport-azure-ad
28
29## 4. Usage
30
31This library contains two strategies: OIDCStrategy and BearerStrategy.
32
33OIDCStrategy uses OpenID Connect protocol for web application login purposes. It works in the following manner:
34If a user is not logged in, passport sends an authentication request to AAD (Azure Active Directory), and AAD prompts the user for his or her sign-in credentials. On successful authentication, depending on the flow you choose, web application will eventually get an id_token back either directly from the AAD authorization endpoint or by redeeming a code at the AAD token endpoint. Passport then validates the id_token and propagates the claims in id_token back to the verify callback, and let the framework finish the remaining authentication procedure. If the whole process is successful, passport adds the user information to `req.user` and passes it to the next middleware. In case of error, passport either sends back an unauthorized response or redirects the user to the page you specified (such as homepage or login page).
35
36BearerStrategy uses Bearer Token protocol to protect web resource/api. It works in the following manner:
37User sends a request to the protected web api which contains an access_token in either the authorization header or body. Passport extracts and validates the access_token, and propagates the claims in access_token to the verify callback and let the framework finish the remaining authentication procedure. On successful authentication, passport adds the user information to `req.user` and passes it to the next middleware, which is usually the business logic of the web resource/api. In case of error, passport sends back an unauthorized response.
38
39
40We support AAD v1, v2 and B2C tenants for both strategies. Please check out [section 8](#8-samples-and-documentation) for the samples. You can manage v1 tenants and register applications at https://manage.windowsazure.com. For v2 tenants and applications, you should go to https://aka.ms/appregistrations. For B2C tenants, go to https://manage.windowsazure.com and click 'Manage B2C settings' to register applications and policies.
41
42### 4.1 OIDCStrategy
43
44#### 4.1.1 Configure strategy and provide callback function
45
46##### 4.1.1.1 Sample using the OIDCStrategy
47
48```javascript
49passport.use(new OIDCStrategy({
50 identityMetadata: config.creds.identityMetadata,
51 clientID: config.creds.clientID,
52 responseType: config.creds.responseType,
53 responseMode: config.creds.responseMode,
54 redirectUrl: config.creds.redirectUrl,
55 allowHttpForRedirectUrl: config.creds.allowHttpForRedirectUrl,
56 clientSecret: config.creds.clientSecret,
57 validateIssuer: config.creds.validateIssuer,
58 isB2C: config.creds.isB2C,
59 issuer: config.creds.issuer,
60 passReqToCallback: config.creds.passReqToCallback,
61 scope: config.creds.scope,
62 loggingLevel: config.creds.loggingLevel,
63 loggingNoPII: config.creds.loggingNoPII,
64 nonceLifetime: config.creds.nonceLifetime,
65 nonceMaxAmount: config.creds.nonceMaxAmount,
66 useCookieInsteadOfSession: config.creds.useCookieInsteadOfSession,
67 cookieSameSite: config.creds.cookieSameSite, // boolean
68 cookieEncryptionKeys: config.creds.cookieEncryptionKeys,
69 clockSkew: config.creds.clockSkew,
70 proxy: { port: 'proxyport', host: 'proxyhost', protocol: 'http' },
71 },
72 function(iss, sub, profile, accessToken, refreshToken, done) {
73 if (!profile.oid) {
74 return done(new Error("No oid found"), null);
75 }
76 // asynchronous verification, for effect...
77 process.nextTick(function () {
78 findByOid(profile.oid, function(err, user) {
79 if (err) {
80 return done(err);
81 }
82 if (!user) {
83 // "Auto-registration"
84 users.push(profile);
85 return done(null, profile);
86 }
87 return done(null, user);
88 });
89 });
90 }
91));
92```
93
94##### 4.1.1.2 Options
95
96* `identityMetadata` (Required)
97
98 The metadata endpoint provided by the Microsoft Identity Portal that provides the keys and other important information at runtime. Examples:
99 * v1 tenant-specific endpoint
100 ```
101 https://login.microsoftonline.com/your_tenant_name.onmicrosoft.com/.well-known/openid-configuration
102 https://login.microsoftonline.com/your_tenant_guid/.well-known/openid-configuration
103 ```
104 * v1 common endpoint
105 ```
106 https://login.microsoftonline.com/common/.well-known/openid-configuration
107 ```
108 * v2 tenant-specific endpoint
109 ```
110 https://login.microsoftonline.com/your_tenant_name.onmicrosoft.com/v2.0/.well-known/openid-configuration
111 https://login.microsoftonline.com/your_tenant_guid/v2.0/.well-known/openid-configuration
112 ```
113 * v2 common endpoint
114 ```
115 https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration
116 ```
117
118 For B2C, you cannot use v2 common endpoint unless you specify the tenant in `passport.authenticate` using `tenantIdOrName` option. See section 4.1.3 for more details.
119
120* `clientID` (Required)
121
122 The client ID of your application in AAD (Azure Active Directory)
123
124* `responseType` (Required)
125
126 Must be 'code', 'code id_token', 'id_token code' or 'id_token'. For login only flows you can use 'id_token'; if you want access_token, use 'code', 'code id_token' or 'id_token code'.
127
128* `responseMode` (Required)
129
130 Must be 'query' or 'form_post'. This is how you get code or id_token back. 'form_post' is recommended for all scenarios.
131
132* `redirectUrl` (Required)
133
134 Must be a https url string, unless you set `allowHttpForRedirectUrl` to true. This is the reply URL registered in AAD for your app. Production environment should always use https for `redirectUrl`.
135
136* `passReqToCallback` (Conditional)
137
138 Required to set to true if using `req` as the first paramter in the verify function, default value is false. See section 4.1.1.3 for more details.
139
140* `allowHttpForRedirectUrl` (Conditional)
141
142 Required to set to true if you want to use http url for redirectUrl like `http://localhost:3000`.
143
144* `clientSecret` (Conditional)
145
146 When `responseType` is not `id_token`, we have to provide client credential to redeem the authorization code. This credential could be client secret or client assertion. Non-B2C tenant supports both flows, but B2C tenant only supports client secret flow.
147
148 For B2C tenant: `clientSecret` is required if the `responseType` is not 'id_token'.
149
150 For non-B2C tenant: If `responseType` is not `id_token`, developer must provide either `clientSecret`, or `thumbprint` and `privatePEMKey`. We use `clientSecret` if it is provided; otherwise we use `thumbprint` and `privatePEMKey` for client assertion flow.
151
152 `clientSecret` is the app key of your app in AAD. For B2C, the app key sometimes contains \\, please replace \ with two \\'s in the app key, otherwise \ will be treated as the beginning of an escaping character.
153
154* `thumbprint` (Conditional)
155
156 Required if you want to use client assertion flow. `thumbprint` is the base64url format of the thumbprint (hash value) of the public key.
157
158* `privatePEMKey` (Conditional)
159
160 Required if you want to use client assertion flow. `privatePEMKey` is the private pem key string.
161
162* `isB2C` (Conditional)
163
164 Required to set to true if you are using B2C tenant.
165
166* `validateIssuer` (Conditional)
167
168 Required to set to false if you don't want to validate issuer, default value is true. We validate the `iss` claim in id_token against user provided `issuer` values and the issuer value we get from tenant-specific endpoint. If you use common endpoint for `identityMetadata` and you want to validate issuer, then you have to either provide `issuer`, or provide the tenant for each login request using `tenantIdOrName` option in `passport.authenticate` (see section 4.1.3 for more details).
169
170* `issuer` (Conditional)
171
172 This can be a string or an array of strings. See `validateIssuer` for the situation that requires `issuer`.
173
174* `jweKeyStore` (Conditional)
175
176 This option is required if you want to accept and decrypt id_token in JWE Compact Serialization format. See
177 section 4.1.1.4 for more details.
178
179* `useCookieInsteadOfSession` (Conditional)
180
181 Passport-azure-ad saves state and nonce in session by default for validation purpose. Consider regenerating the session
182 after authentication to prevent session fixation attacks when using the default. If `useCookieInsteadOfSession` is set to
183 true, passport-azure-ad will encrypt the state/nonce and put them into cookie instead. This is helpful when we want to be
184 completely session-free, in other words, when you use { session: false } option in passport.authenticate function.
185 If `useCookieInsteadOfSession` is set to true, you must provide `cookieEncryptionKeys` for cookie encryption and decryption.
186* `cookieSameSite` (Conditional)
187 If set to true, Passport will add the Same-Site: None header to cookies set by the lib, specifically to validate state and nonce.
188* `cookieEncryptionKeys` (Conditional)
189
190 If `useCookieInsteadOfSession` is set to true, you must provide `cookieEncryptionKeys`. It is an array of the following format: [ {key: '...', 'iv': '...' }, {key: '...', 'iv': '...' }, ...]. key could be any string of length 32, and iv could be any string of length 12. We always use the first set of key/iv to encrypt cookie, but we try all the key/iv to decrypt cookie.
191 This is helpful if you want to do key rollover. The encryption/decryption algorithm we use is aes-256-gcm. You can limit the cookie amount and expiration using `nonceLifetime` and `nonceMaxAmount` options.
192
193* `scope` (Optional)
194
195 List of scope values besides `openid` indicating the required scope of the access token for accessing the requested resource. For example, ['email', 'profile']. If you need refresh_token for v2 endpoint, then you have to include the 'offline_access' scope.
196
197* `loggingLevel` (Optional)
198
199 Logging level. 'info', 'warn' or 'error'.
200
201* `loggingNoPII` (Optional)
202
203 If this is set to true, no personal information such as tokens and claims will be logged. The default value is true.
204
205* `nonceLifetime` (Optional)
206
207 The lifetime of nonce in session in seconds. The default value is 3600 seconds.
208
209* `nonceMaxAmount` (Optional)
210
211 The max amount of nonce you want to keep in session or cookies. The default number is 10. The oldest nonce(s) will be removed if the total number exceeds. (You can keep this number very small because nonce will be removed from session or cookies after validation. This mainly handles the case when user opens more than one login tabs at once and wants to go back to the first login page to type user credentials. Each login tab results in a nonce in session or cookie, so we only honor the most recent nonceMaxAmount many login tabs.)
212
213* `clockSkew` (Optional)
214
215 This value is the clock skew (in seconds) allowed in token validation. It must be a positive integer. The default value is 300 seconds.
216
217##### 4.1.1.3 Verify callback
218
219If you set `passReqToCallback` option to false, you can use one of the following signatures for the verify callback
220
221```
222 function(iss, sub, profile, jwtClaims, access_token, refresh_token, params, done)
223 function(iss, sub, profile, access_token, refresh_token, params, done)
224 function(iss, sub, profile, access_token, refresh_token, done)
225 function(iss, sub, profile, done)
226 function(iss, sub, done)
227 function(profile, done)
228```
229
230If you set `passReqToCallback` option to true, you can use one of the following signatures for the verify callback
231
232```
233 function(req, iss, sub, profile, jwtClaims, access_token, refresh_token, params, done)
234 function(req, iss, sub, profile, access_token, refresh_token, params, done)
235 function(req, iss, sub, profile, access_token, refresh_token, done)
236 function(req, iss, sub, profile, done)
237 function(req, iss, sub, done)
238 function(req, profile, done)
239```
240
241#### 4.1.1.4 JWE support
242
243 We support encrypted id_token in JWE Compact Serialization format.
244
245 The key encryption algorithms supported are:
246
247 `RSA1_5`, `RSA-OAEP`, `A128KW`, `A256KW`, `dir`.
248
249 The content encryption algorithms supported are:
250
251 `A128CBC-HS256`, `A192CBC-HS384`, `A256CBC-HS512`, `A128GCM`, and `A256GCM`.
252
253 In order to decrypt the id_token, keys have to be provided in JWK format using `jweKeyStore` option. We will first
254 try the key with the corresponding kid. If decryption fails, we will try every possible key in `jweKeyStore`.
255 The following is an example of `jweKeyStore`:
256
257 ```javascript
258
259 jweKeyStore: [
260 { 'kid': 'sym_key_256', 'kty': 'oct', 'k': 'WIVds2iwJPwNhgUgwZXmn/46Ql1EkiL+M+QqDRdQURE=' },
261 { 'kid': 'sym_key_128', 'kty': 'oct', 'k': 'GawgguFyGrWKav7AX4VKUg'},
262 { 'kid': 'sym_key_384', 'kty': 'oct', 'k': 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4v'},
263 { 'kid': 'rsa_key',
264 'kty': 'RSA',
265 "n":"6-FrFkt_TByQ_L5d7or-9PVAowpswxUe3dJeYFTY0Lgq7zKI5OQ5RnSrI0\n\
266 T9yrfnRzE9oOdd4zmVj9txVLI-yySvinAu3yQDQou2Ga42ML_-K4Jrd5cl\n\
267 MUPRGMbXdV5Rl9zzB0s2JoZJedua5dwoQw0GkS5Z8YAXBEzULrup06fnB5\n\
268 n6x5r2y1C_8Ebp5cyE4Bjs7W68rUlyIlx1lzYvakxSnhUxSsjx7u_mIdyw\n\
269 yGfgiT3tw0FsWvki_KYurAPR1BSMXhCzzZTkMWKE8IaLkhauw5MdxojxyB\n\
270 VuNY-J_elq-HgJ_dZK6g7vMNvXz2_vT-SykIkzwiD9eSI9UWfsjw",
271 "e":"AQAB",
272 "d":"C6EGZYf9U6RI5Z0BBoSlwy_gKumVqRx-dBMuAfPM6KVbwIUuSJKT3ExeL5\n\
273 P0Ky1b4p-j2S3u7Afnvrrj4HgVLnC1ks6rEOc2ne5DYQq8szST9FMutyul\n\
274 csNUKLOM5cVromALPz3PAqE2OCLChTiQZ5XZ0AiH-KcG-3hKMa-g1MVnGW\n\
275 -SSmm27XQwRtUtFQFfxDuL0E0fyA9O9ZFBV5201ledBaLdDcPBF8cHC53G\n\
276 m5G6FRX3QVpoewm3yGk28Wze_YvNl8U3hvbxei2Koc_b9wMbFxvHseLQrx\n\
277 vFg_2byE2em8FrxJstxgN7qhMsYcAyw1qGJY-cYX-Ab_1bBCpdcQ",
278 "p":"_avCCyuo7hHlqu9Ec6R47ub_Ul_zNiS-xvkkuYwW-4lNnI66A5zMm_BOQV\n\
279 MnaCkBua1OmOgx7e63-jHFvG5lyrhyYEmkA2CS3kMCrI-dx0fvNMLEXInP\n\
280 xd4np_7GUd1_XzPZEkPxBhqf09kqryHMj_uf7UtPcrJNvFY-GNrzlJk",
281 "q":"7gvYRkpqM-SC883KImmy66eLiUrGE6G6_7Y8BS9oD4HhXcZ4rW6JJKuBzm\n\
282 7FlnsVhVGro9M-QQ_GSLaDoxOPQfHQq62ERt-y_lCzSsMeWHbqOMci_pbt\n\
283 vJknpMv4ifsQXKJ4Lnk_AlGr-5r5JR5rUHgPFzCk9dJt69ff3QhzG2c",
284 "dp":"ErP3OpudePAY3uGFSoF16Sde69PnOra62jDEZGnPx_v3nPNpA5sr-tNc8\n\
285 bQP074yQl5kzSFRjRlstyW0TpBVMP0ocbD8RsN4EKsgJ1jvaSIEoP87Ox\n\
286 duGkim49wFA0Qxf_NyrcYUnz6XSidY3lC_pF4JDJXg5bP_x0MUkQCTtQE",
287 "dq":"YbBsthPt15Pshb8rN8omyfy9D7-m4AGcKzqPERWuX8bORNyhQ5M8JtdXc\n\
288 u8UmTez0j188cNMJgkiN07nYLIzNT3Wg822nhtJaoKVwZWnS2ipoFlgrB\n\
289 gmQiKcGU43lfB5e3qVVYUebYY0zRGBM1Fzetd6Yertl5Ae2g2CakQAcPs",
290 "qi":"lbljWyVY-DD_Zuii2ifAz0jrHTMvN-YS9l_zyYyA_Scnalw23fQf5WIcZ\n\
291 ibxJJll5H0kNTIk8SCxyPzNShKGKjgpyZHsJBKgL3iAgmnwk6k8zrb_lq\n\
292 a0sd1QWSB-Rqiw7AqVqvNUdnIqhm-v3R8tYrxzAqkUsGcFbQYj4M5_F_4"
293 },
294 { 'kid': 'ras_key_2',
295 'kty': 'RSA',
296 'privatePemKey':
297 '-----BEGIN RSA PRIVATE KEY-----\n\
298 MIIEowIBAAKCAQEA6+FrFkt/TByQ/L5d7or+9PVAowpswxUe3dJeYFTY0Lgq7zKI\n\
299 5OQ5RnSrI0T9yrfnRzE9oOdd4zmVj9txVLI+yySvinAu3yQDQou2Ga42ML/+K4Jr\n\
300 d5clMUPRGMbXdV5Rl9zzB0s2JoZJedua5dwoQw0GkS5Z8YAXBEzULrup06fnB5n6\n\
301 x5r2y1C/8Ebp5cyE4Bjs7W68rUlyIlx1lzYvakxSnhUxSsjx7u/mIdywyGfgiT3t\n\
302 w0FsWvki/KYurAPR1BSMXhCzzZTkMWKE8IaLkhauw5MdxojxyBVuNY+J/elq+HgJ\n\
303 /dZK6g7vMNvXz2/vT+SykIkzwiD9eSI9UWfsjwIDAQABAoIBAAuhBmWH/VOkSOWd\n\
304 AQaEpcMv4CrplakcfnQTLgHzzOilW8CFLkiSk9xMXi+T9CstW+Kfo9kt7uwH5766\n\
305 4+B4FS5wtZLOqxDnNp3uQ2EKvLM0k/RTLrcrpXLDVCizjOXFa6JgCz89zwKhNjgi\n\
306 woU4kGeV2dAIh/inBvt4SjGvoNTFZxlvkkpptu10MEbVLRUBX8Q7i9BNH8gPTvWR\n\
307 QVedtNZXnQWi3Q3DwRfHBwudxpuRuhUV90FaaHsJt8hpNvFs3v2LzZfFN4b28Xot\n\
308 iqHP2/cDGxcbx7Hi0K8bxYP9m8hNnpvBa8SbLcYDe6oTLGHAMsNahiWPnGF/gG/9\n\
309 WwQqXXECgYEA/avCCyuo7hHlqu9Ec6R47ub/Ul/zNiS+xvkkuYwW+4lNnI66A5zM\n\
310 m/BOQVMnaCkBua1OmOgx7e63+jHFvG5lyrhyYEmkA2CS3kMCrI+dx0fvNMLEXInP\n\
311 xd4np/7GUd1/XzPZEkPxBhqf09kqryHMj/uf7UtPcrJNvFY+GNrzlJkCgYEA7gvY\n\
312 RkpqM+SC883KImmy66eLiUrGE6G6/7Y8BS9oD4HhXcZ4rW6JJKuBzm7FlnsVhVGr\n\
313 o9M+QQ/GSLaDoxOPQfHQq62ERt+y/lCzSsMeWHbqOMci/pbtvJknpMv4ifsQXKJ4\n\
314 Lnk/AlGr+5r5JR5rUHgPFzCk9dJt69ff3QhzG2cCgYASs/c6m5148Bje4YVKgXXp\n\
315 J17r0+c6trraMMRkac/H+/ec82kDmyv601zxtA/TvjJCXmTNIVGNGWy3JbROkFUw\n\
316 /ShxsPxGw3gQqyAnWO9pIgSg/zs7F24aSKbj3AUDRDF/83KtxhSfPpdKJ1jeUL+k\n\
317 XgkMleDls//HQxSRAJO1AQKBgGGwbLYT7deT7IW/KzfKJsn8vQ+/puABnCs6jxEV\n\
318 rl/GzkTcoUOTPCbXV3LvFJk3s9I9fPHDTCYJIjdO52CyMzU91oPNtp4bSWqClcGV\n\
319 p0toqaBZYKwYJkIinBlON5XweXt6lVWFHm2GNM0RgTNRc3rXemHq7ZeQHtoNgmpE\n\
320 AHD7AoGBAJW5Y1slWPgw/2bootonwM9I6x0zLzfmEvZf88mMgP0nJ2pcNt30H+Vi\n\
321 HGYm8SSZZeR9JDUyJPEgscj8zUoShio4KcmR7CQSoC94gIJp8JOpPM62/5amtLHd\n\
322 UFkgfkaosOwKlarzVHZyKoZvr90fLWK8cwKpFLBnBW0GI+DOfxf+\n\
323 -----END RSA PRIVATE KEY-----\n';
324 }
325 ]
326
327 ```
328
329
330#### 4.1.2 Use `passport.authenticate` to protect routes
331
332To complete the sample, provide a route that corresponds to the path
333configuration parameter that is sent to the strategy:
334
335```javascript
336
337app.get('/login',
338 passport.authenticate('azuread-openidconnect', { failureRedirect: '/' }),
339 function(req, res) {
340 log.info('Login was called in the Sample');
341 res.redirect('/');
342});
343
344function regenerateSessionAfterAuthentication(req, res, next) {
345 var passportInstance = req.session.passport;
346 return req.session.regenerate(function (err){
347 if (err) {
348 return next(err);
349 }
350 req.session.passport = passportInstance;
351 return req.session.save(next);
352 });
353}
354
355// POST /auth/openid/return
356// Use passport.authenticate() as route middleware to authenticate the
357// request. If authentication fails, the user will be redirected back to the
358// home page. Otherwise, the primary route function function will be called,
359// which, in this example, will redirect the user to the home page.
360app.post('/auth/openid/return',
361 passport.authenticate('azuread-openidconnect', { failureRedirect: '/' }),
362 regenerateSessionAfterAuthentication,
363 function(req, res) {
364 res.redirect('/');
365 });
366
367app.get('/logout', function(req, res){
368 req.logout();
369 res.redirect('/');
370});
371
372```
373
374#### 4.1.3 Options available for `passport.authenticate`
375
376* `failureRedirect`: the url redirected to when the authentication fails
377
378* `session`: if you don't want a persistent login session, you can use `session: false`. The default value is true.
379
380* `customState`: if you want to use a custom state value instead of a random generated one
381
382* `resourceURL`: if you need access_token for some resource. Note this option is only for v1 endpoint and `code`, `code id_token`, `id_token code` flow. For v2 endpoint, resource is considered as a scope, so it should be specified in the `scope` field when you create
383the strategy.
384
385* `tenantIdOrName`: if you want to specify the tenant to use for this request. You can use the tenant guid or tenant name (like 'contoso.onmicrosoft.com'). Note:
386 * You must use common endpoint for `identityMetadata`, otherwise this option will be ignored. We will fetch and use the metadata from the tenant you specify for this request.
387 * This option only applies to the login request, in other words, the request which is not supposed to contain code or id_token. Passport saves the `tenantIdOrName` value in session before sending the authentication request. When we receive a request containing code or id_token, we retrieve the saved `tenantIdOrName` value from session and use that value.
388 * If you are using B2C common endpoint, then `tenantIdOrName` must be used for every login request.
389
390* `domain_hint`: if you want to specify the domain that the user should use to sign in. This option is not supported for B2C tenant.
391
392* `login_hint`: if you want to prefill the username with a given value in the login page. The value should be the `upn` of a user, not the email (most times they are the same though).
393
394* `prompt`: v1 and v2 endpoint support `login`, `consent` and `admin_consent`; B2C endpoint only supports `login`.
395
396* `response`: this is required if you want to use cookie instead of session to save state/nonce. See section 4.1.4.
397
398Example:
399
400```
401 passport.authenticate('azuread-openidconnect', { failureRedirect: '/', session: false, customState: 'my_state', resourceURL: 'https://graph.microsoft.com/mail.send'});
402
403 passport.authenticate('azuread-openidconnect', { tenantIdOrName: 'contoso.onmicrosoft.com' });
404```
405
406#### 4.1.4 Session free support
407
408Passport framework uses session to keep a persistent login session. As a plug in, we also use session to store state and nonce by default, regardless whether you use { session: false } option in passport.authenticate or not. To be completely session free, you must configure passport-azure-ad to create state/nonce cookie instead of saving them in session. Please follow the following example:
409
410```
411 passport.use(new OIDCStrategy({
412 ...
413 nonceLifetime: 600, // state/nonce cookie expiration in seconds
414 nonceMaxAmount: 5, // max amount of state/nonce cookie you want to keep (cookie is deleted after validation so this can be very small)
415 useCookieInsteadOfSession: true, // use cookie, not session
416 cookieEncryptionKeys: [ { key: '12345678901234567890123456789012', 'iv': '123456789012' }], // encrypt/decrypt key and iv, see `cookieEncryptionKeys` instruction in section 4.1.1.2
417 },
418 // any supported verify callback
419 function(iss, sub, profile, accessToken, refreshToken, done) {
420 ...
421 });
422
423 app.get('/login', passport.authenticate('azuread-openidconnect', { session: false }));
424
425```
426
427### 4.2 BearerStrategy
428
429#### 4.2.1 Configure strategy and provide callback function
430
431##### 4.2.1.1 Sample using the BearerStrategy
432
433```javascript
434
435// We pass these options in to the ODICBearerStrategy.
436
437var options = {
438 identityMetadata: config.creds.identityMetadata,
439 clientID: config.creds.clientID,
440 validateIssuer: config.creds.validateIssuer,
441 issuer: config.creds.issuer,
442 passReqToCallback: config.creds.passReqToCallback,
443 isB2C: config.creds.isB2C,
444 policyName: config.creds.policyName,
445 allowMultiAudiencesInToken: config.creds.allowMultiAudiencesInToken,
446 audience: config.creds.audience,
447 loggingLevel: config.creds.loggingLevel,
448 loggingNoPII: config.creds.loggingNoPII,
449 clockSkew: config.creds.clockSkew,
450 scope: config.creds.scope
451};
452
453var bearerStrategy = new BearerStrategy(options,
454 function(token, done) {
455 log.info('verifying the user');
456 log.info(token, 'was the token retreived');
457 findById(token.oid, function(err, user) {
458 if (err) {
459 return done(err);
460 }
461 if (!user) {
462 // "Auto-registration"
463 log.info('User was added automatically as they were new. Their oid is: ', token.oid);
464 users.push(token);
465 owner = token.oid;
466 return done(null, token);
467 }
468 owner = token.oid;
469 return done(null, user, token);
470 });
471 }
472);
473```
474
475##### 4.2.1.2 Options
476
477* `identityMetadata` (Required)
478
479 The metadata endpoint provided by the Microsoft Identity Portal that provides the keys and other important information at runtime. Examples:
480 * v1 tenant-specific endpoint
481 ```
482 https://login.microsoftonline.com/your_tenant_name.onmicrosoft.com/.well-known/openid-configuration
483 https://login.microsoftonline.com/your_tenant_guid/.well-known/openid-configuration
484 ```
485 * v1 common endpoint
486 ```
487 https://login.microsoftonline.com/common/.well-known/openid-configuration
488 ```
489 * v2 tenant-specific endpoint
490 ```
491 https://login.microsoftonline.com/your_tenant_name.onmicrosoft.com/v2.0/.well-known/openid-configuration
492 https://login.microsoftonline.com/your_tenant_guid/v2.0/.well-known/openid-configuration
493 ```
494 * v2 common endpoint
495 ```
496 https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration
497 ```
498
499 For B2C, you can only use v2 tenant-specific endpoint.
500
501* `clientID` (Required)
502
503 The client ID of your application in AAD (Azure Active Directory)
504
505* `passReqToCallback` (Conditional)
506
507 Required to set to true if using `req` as the first paramter in the verify function, default value is false. See section 4.2.1.3 for more details.
508
509* `isB2C` (Conditional)
510
511 Required to set to true if you are using B2C tenant.
512
513* `policyName` (Conditional)
514
515 Required if you are using B2C tenant. It is a string starting with 'B2C_1_' (case insensitive).
516
517* `validateIssuer` (Conditional)
518
519 Required to set to false if you don't want to validate issuer, default value is true. We validate the `iss` claim in id_token against user provided `issuer` values and the issuer value we get from tenant-specific endpoint. If you use common endpoint for `identityMetadata` and you want to validate issuer, then you must provide `issuer`, or provide `tenantIdOrName` in passport.authenticate.
520
521* `issuer` (Conditional)
522
523 This can be a string or an array of strings. See `validateIssuer` for the situation that requires `issuer`.
524
525* `allowMultiAudiencesInToken` (Conditional)
526
527 Required if you allow access_token whose `aud` claim contains multiple values.
528
529* `scope` (Optional)
530
531 This value is an array of scopes you accept. If this value is provided, we will check if the token contains one of
532 these accepted scopes. If this value is not provided, we won't check token scopes.
533
534* `audience` (Optional)
535
536 Must be a string or an array of strings. We invalidate the `aud` claim in access_token against `audience`. The default value for `audience` is `clientID`.
537
538* `loggingLevel` (Optional)
539
540 Logging level. 'info', 'warn' or 'error'.
541
542* `loggingNoPII` (Optional)
543
544 If this is set to true, no personal information such as tokens and claims will be logged. The default value is true.
545
546* `clockSkew` (Optional)
547
548 This value is the clock skew (in seconds) allowed in token validation. It must be a positive integer. The default value is 300 seconds.
549
550 * `proxy` (optional)
551
552 This value is the proxy settings object: { port: 'proxyport', host: 'proxyhost', protocol: 'http' }
553
554##### 4.2.1.3 Verify callback
555
556If you set `passReqToCallback` option to false, you can use the following verify callback
557
558```
559 function(token, done)
560```
561
562If you set `passReqToCallback` option to true, you can use the following verify callback
563
564```
565 function(req, token, done)
566```
567
568#### 4.2.2 Use `passport.authenticate` to protect resources or APIs
569
570In the following example, we are using passport to protect '/api/tasks'. User sends a GET request to '/api/tasks' with access_token in authorization header or body. Passport validates the access_token, adds the related claims from access_token to `req.user`, and passes the request to listTasks middleware. The listTasks middleware can then read the user information in `req.user` and list all the tasks related to this user. Note that we do authentication every time, so we don't need to keep this user in session, and this can be achieved by using `session: false` option.
571
572```javascript
573 server.get('/api/tasks', passport.authenticate('oauth-bearer', { session: false }), listTasks);
574```
575
576#### 4.2.3 Options available for `passport.authenticate`
577
578* `session`: if you don't want a persistent login session, you can use `session: false`. The default value is true.
579
580* `tenantIdOrName`: if you use common endpoint, you can use this option to dynamically provide the tenant.
581
582Example:
583
584```
585 passport.authenticate('oauth-bearer', { session: false });
586```
587
588## 5. Test
589
590In the library root folder, type the following command to install the dependency packages:
591
592```
593 $ npm install
594```
595
596### 5.1. Run all tests except the end to end tests
597
598Type the following command to run tests:
599
600```
601 $ npm test
602```
603
604### 5.2. Run all tests including the end to end tests
605
606#### 5.2.1. Create test applications
607
608First you need to register one application in v1 tenant, one in v2 tenant and one in B2C tenant.
609
610For the v2 application, you should register it at https://apps.dev.microsoft.com/ instead of Azure Portal.
611
612For the B2C application, create policies named 'B2C_1_signin', 'B2C_1_signup'. For each policy, select 'Local Account' as the identity provider, and select the
613following:
614
615* 'B2C_1_signup':
616
617 * Sign-up attributes: 'Display Name', 'Email Address', 'Given Name', 'Surname'
618
619 * Application claims: 'Display Name', Email Addresses', 'Given Name', 'Identity Provider', 'Surname', 'Users Object ID'
620
621* 'B2C_1_signin':
622
623 * Application claims: 'Display Name', Email Addresses', 'Given Name', 'Identity Provider', 'Surname', 'Users Object ID'
624
625You will also need to click the 'Run now' button in the 'B2C_1_signup' blade to create an user.
626
627For B2C application, you will also need to create at least one scope and provide it to test parameters. See [how to create scope for B2C access token](https://azure.microsoft.com/en-us/blog/azure-ad-b2c-access-tokens-now-in-public-preview/). In the bearer_b2c_test, We will use OIDCStrategy to get a B2C
628access token for the scope, and use BearerStrategy to validate the scope. Note for scope we use the full url in
629 `b2c_params.scopeForOIDC` but only the name in `b2c_params.scopeForBearer`. For example,
630 `b2c_params.scopeForOIDC=['https://sijun1b2c.onmicrosoft.com/oidc-b2c/read']` and `b2c_params.scopeForBearer=['read']`.
631
632#### 5.2.2. Fill the test parameters
633
634Open `test/End_to_end_test/script.js`, set `is_test_parameters_completed` parameter to true. For `test_parameters` variable, fill in the tenant id/client id/client secret of your applications, and the username/password of your application user.
635
636For `thumbprint` and `privatePEMKey` parameters, you need to specify a certificate for your app and register the public key in Azure Active Directory. `thumbprint` is the base64url format of the thumbprint of the public key, and `privatePEMKey` is the private pem key string. For a v1 tenant, you can follow [this post](http://www.andrewconnell.com/blog/user-app-app-only-permissions-client-credentials-grant-flow-in-azure-ad-office-365-apis) to generate a certificate and register the public key. For a v2 tenant, you can go to your application page in the [v2 portal](https://apps.dev.microsoft.com) and click `Generate New Key Pair`. A certificate will be generated for you to download. The corresponding public key is automatically registered in this case.
637
638#### 5.2.3. Run the tests
639
640Type the following commands to run the tests:
641
642```
643 $ cd test/End_to_end_test
644 $ npm install
645 $ npm install grunt -g
646 $ grunt run_tests_with_e2e
647```
648
649Tests will run automatically and in the terminal you can see how many tests are passing/failing. More details can be found [here](https://github.com/AzureAD/passport-azure-ad/blob/master/contributing.md).
650
651## 6. Logging
652#### Personal Identifiable Information (PII) & Organizational Identifiable Information (OII)
653
654By default, passport-azure-ad logging does not capture or log any PII or OII. The library allows app developers to turn this on by configuring `loggingNoPII` in the config options. By turning on PII or OII, the app takes responsibility for safely handling highly-sensitive data and complying with any regulatory requirements.
655
656```javascript
657//PII or OII logging disabled. Default Logger does not capture any PII or OII.
658var options = {
659 ...
660 loggingNoPII: true,
661 ...
662};
663
664//PII or OII logging enabled
665var options = {
666 ...
667 loggingNoPII: false,
668 ...
669};
670```
671
672
673## 7. Samples and Documentation
674
675[We provide a full suite of sample applications and documentation on GitHub](https://azure.microsoft.com/en-us/documentation/samples/?service=active-directory)
676to help you get started with learning the Azure Identity system. This includes
677tutorials for native clients such as Windows, Windows Phone, iOS, OSX, Android,
678and Linux. We also provide full walkthroughs for authentication flows such as
679OAuth2, OpenID Connect, Graph API, and other awesome features.
680
681Azure Identity samples for this plug-in can be found in the following links:
682
683### 7.1 Samples for [OpenID connect strategy](https://github.com/AzureAD/passport-azure-ad/blob/master/lib/oidcstrategy.js)
684
685* [sample using v1 endpoint](https://github.com/AzureADQuickStarts/WebApp-OpenIDConnect-NodeJS)
686
687* [sample using v2 endpoint](https://github.com/AzureADQuickStarts/AppModelv2-WebApp-OpenIDConnect-nodejs)
688
689* [sample using B2C tenant](https://github.com/AzureADQuickStarts/B2C-WebApp-OpenIDConnect-NodeJS)
690
691### 7.2 Samples for [Bearer strategy](https://github.com/AzureAD/passport-azure-ad/blob/master/lib/bearerstrategy.js)
692
693* [sample using v1 endpoint](https://github.com/AzureADQuickStarts/WebAPI-Bearer-NodeJS)
694
695* [sample using v2 endpoint](https://github.com/AzureADQuickStarts/AppModelv2-WebAPI-nodejs)
696
697* [sample using B2C tenant](https://github.com/AzureADQuickStarts/B2C-WebApi-Nodejs)
698
699## 8. Community Help and Support
700
701We leverage [Stack Overflow](http://stackoverflow.com/) to work with the community on supporting Azure Active Directory and its SDKs, including this one. We highly recommend you ask your questions on Stack Overflow (we're all on there!) Also browser existing issues to see if someone has had your question before.
702
703We recommend you use the "msal" tag so we can see it! Here is the latest Q&A on Stack Overflow for MSAL: [http://stackoverflow.com/questions/tagged/msal](http://stackoverflow.com/questions/tagged/msal)
704
705## 9. Security Reporting
706
707If you find a security issue with our libraries or services please report it to [secure@microsoft.com](mailto:secure@microsoft.com) with as much detail as possible. Your submission may be eligible for a bounty through the [Microsoft Bounty](http://aka.ms/bugbounty) program. Please do not post security issues to GitHub Issues or any other public site. We will contact you shortly upon receiving the information. We encourage you to get notifications of when security incidents occur by visiting [this page](https://technet.microsoft.com/en-us/security/dd252948) and subscribing to Security Advisory Alerts.
708
709## 10. Contributing
710
711All code is licensed under the MIT license and we triage actively on GitHub. We enthusiastically welcome contributions and feedback. You can clone the repo and start contributing now.
712
713More details [about contribution](https://github.com/AzureAD/passport-azure-ad/blob/master/contributing.md)
714
715## 11. Releases
716
717Please check the [releases](https://github.com/AzureAD/passport-azure-ad/releases) for updates.
718
719## 12. Acknowledgements
720
721The code is based on Henri Bergius's [passport-saml](https://github.com/bergie/passport-saml) library and Matias Woloski's [passport-wsfed-saml2](https://github.com/auth0/passport-wsfed-saml2) library as well as Kiyofumi Kondoh's [passport-openid-google](https://github.com/kkkon/passport-google-openidconnect).
722
723## 13. License
724Copyright (c) Microsoft Corp. All rights reserved. Licensed under the MIT License;
725
726## 14. Microsoft Open Source Code of Conduct
727
728We Value and Adhere to the Microsoft Open Source Code of Conduct
729
730This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.