Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node express with OpenID connect

I use the this library to use oidc with nodejs

What I need is the following:

  1. user login with user password, or have the data already the session cookie. this is calling to my app root route "/"

  2. I've registered the application already in the authorization server, the auth server should call to my the app/redirect

  3. from the auth server I took the clientId and client secret and put it in the app.

  4. When the user logged-in the auth server should call to my application redirect route .

  5. From the oidc strategy I need to get the tokenset.claims(); and from it tokenset.id_token , the user token. , in the redirect call

It should be with

response_type: 'code',

https://github.com/auth0/express-openid-connect#getting-started

The problem is the getUser function is called (while debug the application) however I got the userIdentity from req.session.userIdentity which is undefined, any idea what could be wrong here?

We are having the same old implementation which using OIDC and it works for the same auth server and clientid and secret.

  const { auth, requiresAuth } = require('express-openid-connect');
  const session = require('express-session');
  const bodyParser = require('body-parser');
    
    module.exports = async (app) => {
    
      const ClientId = process.env.CI;
      const ClientSecret = process.env.CS;
      const URL = process.env.S_URL;
    
      app.use(session({
         name: 'bat-auth',
         secret: 'cookie-secret',
      }));

      app.use(bodyParser.json());
      app.use(bodyParser.urlencoded({ extended: true }));
    
      app.use(auth({
          clientSecret: ClientSecret,
          issuerBaseURL: `${URL}`,
          clientID: ClientId,
          baseURL: process.env.REDT_URL,
          redirectUriPath: '/redirect',  //my app redirect route
          authorizationParams: {
           response_type: 'code',
           response_mode: 'form_post',
           scope: 'openid',
          },
        async handleCallback(req, res, next) {
           req.session.openidTokens = req.openidTokens;
           console.log('---req.openidTokens', req.openidTokens);
           req.session.userIdentity = req.openidTokens.claims();
          next();
        },
        async getUser(req) {
           return req.session.userIdentity;
        },
      }));

  app.get('/', (req, res) => {
    const tokenSet = req.openid.makeTokenSet(req.session.openidTokens);
    console.log(`tokenset root: ${tokenSet}`);

    res.send(req.isAuthenticated() ? 'Logged in' : 'Logged out');
  });
  app.get('/redirect', async (req, res) => {
    const tokenSet = req.openid.makeTokenSet(req.session.openidTokens);
    console.log(`tokenset: ${tokenSet}`);
    console.log('redirect called');
    res.send('redirect called');
  });

I should use form post and at the end, what I need is to get from the tokenset, user.id_token ?

This is what I've, and verified!

  1. ClientID from auth server
  2. ClientSecret from auth server
  3. Config the auth server my app redirect path, which should called me after successful login
  4. I've also the aud key

Btw, while debug the application it doesn't stops add handleCallback function , but it stops on the getUser app first, not sure what could be the reason...

like image 881
Rayn D Avatar asked Aug 08 '20 17:08

Rayn D


Video Answer


2 Answers

It looks like you're trying to read from req.session.userIdentity but you never set it anywhere. You're setting req.session.openidTokens instead.

Based on the example code, you probably want to modify your handleCallback function to the following:

async handleCallback(req, res, next){
  req.session.openidTokens = req.openidTokens;
  console.log('---req.openidTokens', req.openidTokens);
  req.session.userIdentity = req.openidTokens.claims(); // <-- this is required to make your code sample work
  next();
}
like image 55
gcochard Avatar answered Sep 23 '22 16:09

gcochard


A few points from looking at what you've done. You have not made it too easy for people to answer your question, and there is more you can do to improve your own self diagnosis:

RESPONSE MODE

Get rid of this field - I think I'm right in saying this should always be set to 'query' for the Authorization Response and that will be the default value. It is possible that is causing problems.

ASYNC SYNTAX

I could be wrong, but I would start with the exact syntax from the Auth0 page. Sometimes I've made mistakes in this area via the wrong syntax.

handleCallback: async function (req, res, next) {
    req.session.userIdentity = req.openidTokens.claims();
    next();
  },

HTTP DEBUGGING

Tore is 100% right in saying you should trace messages and post any failures here. As an example of how messages should look, see my blog post. This covers the client side Authorization Code Flow (PKCE) rather than the server side Authorization Code Flow, but the messages are very similar.

The wider point here is that if you do not gain an understanding of OAuth messages and token fields, you will be frequently blocked, rather than being able to diagnose your own problems. In your case, perhaps step 7 is not coming back as the expected query parameter and the library is failing as a result?

HOW TO CAPTURE HTTP MESSAGES

Can you update your config along the same lines as my NodeJS API by adding the following type of configuration, then running a tool such as Fiddler or Charles. You should then be able to capture OAuth messages between your web back end and the Authorization Server, then post any failing ones back here:

auth({
  client_id: 'qhuefhuef',
  ...,
  httpOptions: {
    agent: TunnelAgent.httpsOverHttp({
      proxy: Url.parse('http://127.0.0.1:8888'),
    })
  }

It is well worth taking a bit of time out to get this working, and will benefit all future development in this area. Some further details in my HTTP debugging write up.

ERROR HANDLING

Another possibility is that the Authorization Server is returning an error response in the standard 'error' / 'error_description' fields and you are not handling them.

Don't be satisfied once you've solved your immediate problem. There are multiple moving parts to OAuth solutions, and intermittent problems happen, which you will want to be able to resolve quickly once you deploy your app to testers or production.

I always recommend making OAuth messages fail during the development process, then ensuring that you are capturing the right data and in control of UI error reporting. See steps 10 and 17 of my write up for an approach to testing the points of failure.

like image 30
Gary Archer Avatar answered Sep 22 '22 16:09

Gary Archer