Azure-Samples / active-directory-javascript-nodejs-webapi-v2

A small Node.js Web API that is protected with Azure AD v2.0 to validate access tokens and accepts authorized calls using Passport.js
MIT License
75 stars 40 forks source link

req.user is undefined #12

Closed DarkLite1 closed 4 years ago

DarkLite1 commented 4 years ago

I'm having a similar issue as this one. Following the example I have this code in index.ts:

import 'reflect-metadata'
import 'tsconfig-paths/register'
import express from 'express'
import passport from 'passport'
import { BearerStrategy, } from 'passport-azure-ad'
import { ENVIRONMENT } from '@environment'
import { createConnections } from 'typeorm'
import { getApolloServer } from '@utils/apollo'
import cors from 'cors'

const app = express()

const bearerStrategy = new BearerStrategy(
  {
    identityMetadata: 'https://login.microsoftonline.com/xxx-xxx-xxx-xxx-xxx/v2.0/.well-known/openid-configuration',
    clientID: 'xxx-xxx-xxx-xxx-xxx',
    validateIssuer: false,
    loggingLevel: 'info',
    passReqToCallback: false,
  },
  (token, done) => {
    // Send user info using the second argument
    done(null, {}, token)
  }
)
app.use(cors({ origin: true }))
app.use(passport.initialize())
passport.use(bearerStrategy)

app.use(
  passport.authenticate('oauth-bearer', { session: false }),
  (req, res, next) => {
    console.log('User info: ', req.user)
    console.log('Validated claims: ', req.authInfo)
    next()
  }
)
;(async () => {
  try {
    await createConnections()
    const server = await getApolloServer()
    server.applyMiddleware({ app, cors: false })

    app
      .listen({ port: ENVIRONMENT.port }, () => {
       console.log( `Server ready at http://localhost:${ENVIRONMENT.port}${server.graphqlPath}` )
      })
      .on('error', function (error) { throw `Failed starting Express server on port ${ENVIRONMENT.port}: ${error}` })
  } catch (error) {
    console.error(`Failed starting server: ${error}`);  process.exit(1)
  }
})()

Which results in these console logs:

User info:  {}
Validated claims:  {
  aud: 'xxx-xxx-xxx-xxx-xxx',
  iss: 'https://login.microsoftonline.com/xxx-xxx-xxx-xxx-xxx/v2.0',
  iat: 1595582006,
  nbf: 1595582006,
  exp: 1595585906,
  aio: 'xxx/xxx/xxx/xxx/',
  azp: 'xxx-xxx-xxx-xxx-xxx',
  azpacr: '0',
  name: 'Bond, James (London) GBR',
  oid: 'xxx-xxx-xxx-xxx-xxx',
  preferred_username: 'James.Bond@mi6.co.uk',
  rh: 'x.xxxxxxxxx.',
  scp: 'access_as_user',
  sub: 'x-x-xxx-xxx-xxx',
  tid: 'xxx-xxx-xxx-xxx-xxx',
  uti: 'xxx-xxx',
  ver: '2.0'
}

Notice that he req.user is undefined. According to the documentation I would expect passport to set this for us? Or am I missing something here? To store the user in the database we should probably use the field oid as unique identifier?

A similar question on StackOverlflow.

Thank you for your help.

derisen commented 4 years ago

@DarkLite1 sorry this went unattended. So the req.user attribute is usually populated with session information about an authenticated user, but sessions are not common/appropriate for web API's, as API servers typically require credentials (i.e. token) to be supplied with each request. As such, our sample is not covering this.

If you have some custom logic for populating req.user after an authorized call, you could do so at line 18 in index.js:

const bearerStrategy = new BearerStrategy(config,
    function (token, done) {
        // Send user info using the second argument
        done(null, { /* USER INFO */ }, token);
    }
);

But for sessions you should take a look at a web app sample. You can see some such samples here.

Let me know if you need anything further.

derisen commented 4 years ago

Closing this due to inactivity. Let us know if that doesn't solve your issue.