Node express with OpenID connect
Asked Answered
N

2

10

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...

Nikolos answered 8/8, 2020 at 17:30 Comment(11)
Can you please improve the question? What is is you want to achieve?Cordy
@ToreNestenius - as requested ive update my question with the stesp, is it more clear now? if something isnt clear please let me knowNikolos
Should the redirectUriPath not be: '/redirect'? With a / in-front? you have to be careful when you should use absolute or relative URLs. I would check using tools like Fidder to capture the traffic and then add the failing request in your question.Cordy
@ToreNestenius - thanks for the hint, I tried with '/redirect' also and still got the same error, any other idea? does my other configuration looks ok?Nikolos
I would check using tools like Fidder to capture the traffic and then add the failing request in your question. Then its easier for us to figure out where in the flow you are stuck.Cordy
@ToreNestenius - I didnt see anyhing that could help, if you have something specific that I should check, please let me knowNikolos
You could post sample copies of the various requests captured by a proxy like Fiddler, that would sure help out in debugging the issue.Cordy
I would also try to make this url absolute (including HTTPS and the domain) redirectUriPath: '/redirect',Cordy
@ToreNestenius - when I use fiddler I got it record everything(lots of calls in few seconds), can I recored only my request ?Nikolos
@ToreNestenius - I've tried to use request and what i see only one entry with interal server error, which is coming from my app as im not getting those propertiesNikolos
@RaynD I am also stuck in this situation. Have you got any solution ? Or moved to some thing else ?Jodijodie
S
1

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();
}
Sunil answered 14/8, 2020 at 17:57 Comment(3)
Thanks, I try it and it doesnt works either, while debug the application it doesnt stopes in the handleCallback it just stops on getUser so the code you have provided will not work, any idea why it doesnt stops?Nikolos
Any idea how to proceed ?Nikolos
I would take the example code verbatim and verify it works, then make small, incremental changes until you get to the state you need.Sunil
L
1

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.

Loblolly answered 18/8, 2020 at 7:54 Comment(11)
when I remove the response_mode, I got error: Error: Response mode "form_post" is not supported by the issuer. Supported response modes are "query", "fragment". therefore I've tried to use query which Im not sure is the right...Nikolos
response_mode = query represents how an authorization code is received when using the authorization code flow, as in step 7 of my write up. A form post is then used to swap the code for tokens, but you don't specify that. See also section 4.1.2 of official specs.Loblolly
At the end what I need is the user.id_tokenNikolos
I've change it to only use: authorizationParams: { scope: 'openid', }, and still get the error: Error: Response mode "form_post" is not supported by the issuer. Supported response modes are "query", "fragment".Nikolos
should I try something else?Nikolos
Maybe set 'response_mode=query' explicitly. We then need to look at messages between your web back end and the Authorization Server. Which provider are you using by the way? Eg Auth0 / Azure AD / AWS Cognito? The assumption is that the one you are using supports standard messages.Loblolly
I added a note to my original message on capturing OAuth messages in Server Side NodeJS. Maybe see if you can get that working - if so you'll be able to see any failing messages and also post them here.Loblolly
I've added the 'response_mode=query and got the same results, im trying to configure the` agent`Nikolos
should I use this module github.com/request/tunnel-agent ?Nikolos
and what should I put in the Url.parse('http://127.0.0.1:8888'), I got error message Url Is undefinedNikolos
Download my API GitHub repo from above and see how that works - you will need to install a couple of npm packages (url / tunnel-agent). The main thing is to understand the approach and the goal of having better visibility of messages - of course you may choose to do some things a little differently.Loblolly

© 2022 - 2024 — McMap. All rights reserved.