0

I am building a node app with a express backend. One of the requirements is using Azure AD for authentication. I've installed the passport-azure-ad module and have set it up as the following:

import * as passportAD from "passport-azure-ad";
// ... <snip> ....
const tenantName = "<MY_TENANT_NAME>"";
const clientID = "<MY_CLIENT_ID>";

app.use(passport.initialize());
app.use(passport.session());
const bearerStrategy = new passportAD.BearerStrategy(
  {
    identityMetadata: `https://login.microsoftonline.com/${tenantName}.onmicrosoft.com/.well-known/openid-configuration`,
    clientID
  },
  (token: any, done: any) => {
    console.log(token);
    return done(null, {}, token);
  }
);
passport.use(bearerStrategy);

Then I have added authorization to a route like this:

const myHandler = () => (req, res) => return res.json({});
app.get('/my/route',
        passport.authenticate("oauth-bearer", { session: false }),
        myHandler()
);

This is returning a 401 status as expected however, I haven't been able to find documentation on how to issue a token to a client from Azure AD. I'd like to accept a POST to a login endpoint with a username and password in the body and return a Azure AD token. Is this possible?

Eric Barbour
  • 205
  • 2
  • 9

3 Answers3

6

You can also do the following. I have recently implemented one with my react application with nodejs backend

You can find the key values for BearerStrategyOptions at https://github.com/AzureADQuickStarts/AppModelv2-WebAPI-nodejs/blob/master/node-server/config.js

Allow FYI I used the following common endpoint 'https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration for identityMetadata

const BearerStrategyOptions = {
  identityMetadata,
  clientID,
  validateIssuer,
  issuer,
  passReqToCallback,
  allowMultiAudiencesInToken,
  audience
};

You can find the key values for OIDCStrategyOptions at https://github.com/AzureADQuickStarts/AppModelv2-WebApp-OpenIDConnect-nodejs/blob/master/config.js

const OIDCStrategyOptions = {
  identityMetadata,
  clientID,
  responseType,
  responseMode,
  redirectUrl,
  allowHttpForRedirectUrl,
  clientSecret,
  validateIssuer,
  isB2C,
  issuer,
  passReqToCallback,
  scope,
  nonceLifetime,
  nonceMaxAmount,
  useCookieInsteadOfSession,
  cookieEncryptionKeys,
  clockSkew
};

For Authentication:

 passport.use(
    new OIDCStrategy(OIDCStrategyOptions, function(
      iss,
      sub,
      profile,
      accessToken,
      refreshToken,
      done
    ) {
      if (!profile.oid) {
        return done(new Error("No oid found"), null);
      }
      // asynchronous verification, for effect...
      process.nextTick(function() {
        findByOid(profile.oid, function(err, user) {
          if (err) {
            return done(err);
          }
          if (!user) {
            // "Auto-registration"
            users.push(profile);
            // console.log("---------profile----------", profile)
            return done(null, profile);
          }
          // console.log("-----------user---------", user)
          return done(null, user);
        });
      });
    })
  );

For Authorization:

passport.use(
    new BearerStrategy(BearerStrategyOptions, function(token, done) {
      console.log("verifying the user");
      console.log(token, "was the token retreived");
      findByOid(token.oid, function(err, user) {
        if (err) {
          return done(err);
        }
        if (!user) {
          // "Auto-registration"
          console.log(
            "User was added automatically as they were new. Their oid is: ",
            token.oid
          );
          users.push(token);
          owner = token.oid;
          return done(null, token);
        }
        owner = token.oid;
        return done(null, user, token);
      });
    })
  );

And to authorize the routes use the following code in your api

 passport.authenticate('oauth-bearer', {session: false})

Done! Hope this helps :) for someone looking to use passport-azure-ad

Dinesh Nadimpalli
  • 1,441
  • 1
  • 13
  • 23
0

The only issuer of an Azure AD token is Azure AD. You should not collect username/password in your clients, and you should not accept them in your service.

Your client applications simply needs to use MSAL (or ADAL, or any OpenID Connect client library) to send the user to Azure AD, have them sign in, and in response get an access token for your API.

For example, if you client were a JavaScript single-page app, with MSAL for JavaScript you could do the following:

var userAgentApplication = new Msal.UserAgentApplication(
    '0813e1d1-ad72-46a9-8665-399bba48c201', // AppId of you client app
    null, function (errorDes, token, error, tokenType, instance) {
        // This callback only used loginRedirect OR acquireTokenRedirect.
    }
);

var scopes = ["https://api.example.com/permission.scope"];
userAgentApplication.loginPopup(scopes).then(function (token) {

    // Get the signed-in user
    var user = userAgentApplication.getUser();

    // Get an access token for the signed-in user
    userAgentApplication.acquireTokenSilent(scopes).then(function (token) {

        // Use the access token to call your API
        $.ajax({
            url: 'https://api.example.com/foo',
            type: 'GET',
            dataType: 'json',
            headers: { 'Authorization': 'Bearer ' + token },
            contentType: 'application/json; charset=utf-8',
            success: function (result) {
                // TODO: Do something cool with the API response.
            },
            error: function (error) {
                // TODO: Do something smart if there's an error
            }
        });
    }, function (error) {
        // TODO: Silent token acquisition failed, retry with acquireTokenPopup()
    });
}, function (error) {
    // TODO: Deal with error.
});

(Of course, you can do this for various other platforms.)

Philippe Signoret
  • 13,299
  • 1
  • 40
  • 58
  • Thanks, this is really helpful. Do you know if it is possible to style the loginPopup? – Eric Barbour Oct 12 '18 at 13:56
  • Not really. You can add a logo for your app, but the styling will be whatever styling has been defined by the organization for the user who is signing in (and there's only a little that can actually be styled). – Philippe Signoret Oct 12 '18 at 13:59
-2

To passport-azure-ad module, about how the azure ad issue a token, you could refer to doc1 and doc2.

I'd like to accept a POST to a login endpoint with a username and password in the body and return a Azure AD token. Is this possible?

Yes, it is possible. If you want to do this way, you could refer to here.

SunnySun
  • 1,900
  • 1
  • 6
  • 8