panva / openid-client

OAuth 2 / OpenID Connect Client API for JavaScript Runtimes
MIT License
1.83k stars 392 forks source link

Best practise of using node-openid-client #282

Closed astrixj closed 4 years ago

astrixj commented 4 years ago

Hi,

Is there any tutorial or docs which describe how to work with node-openid-client according to best practices? Why I ask for it.

Currently to make e2e works you need to use few other components such as passport , express-session etc. I really want to avoid it as (as much as possible) as the bring noise to the system e.g. if you change the order of some middle-wares it will stop working. I see the docs of V3 but it will be great if there is some minimum working example which we can use according to the lib recommendation.

panva commented 4 years ago

openid-client is completely framework agnostic, there’s no best practice because there’s no one and best way to write services in Node. The quick start in the readme does explain an e2e flow well and generic enough that you can apply it to your web framework of choice.

This client, think of it as a stepping stone, a core lib for framework/usecase oriented libraries, such as what express-openid-connect is for express authentication using OIDC.

You can absolutely use this library directly, but its expected of you to know how OIDC flows first and then the quick start and API documentation is all you need. Obviously while also knowing your web framework.

And aside, you should definitely consider avoiding passport at all costs, if you think you need passport to use this module, you got the wrong idea. Dunno where.

astrixj commented 4 years ago

@panva - I took your suggestion and try to implement the oidc without passport, however it seems that there issue with the library or Im missing something

This is our code which is working, the auth server calling the redirect route and I was able to get the user id_token

const passport = require('passport');
const expressSesssion = require('express-session');
const { Issuer, Strategy } = require('openid-client');

module.exports = async (app) => {

  let openidCfg;
  openidCfg = {
    scope: 'openid',
    redirect_uri: process.env.RDR_URI,
    response_type: 'code',
    response_mode: 'form_post'
  };

  Issuer.defaultHttpOptions = {
    timeout: 2000,
    retries: 2,
    followRedirect: true
  };

  Issuer.discover(`${(process.env.NVM_URL)}/.well-known/openid-configuration`)
    .then((criiptoIssuer) => {
      const client = new criiptoIssuer.Client({
        client_id: process.env.NVS_CI,
        client_secret: process.env.NVM_CS,
        redirect_uris: [process.env.RDR_URI],
        token_endpoint_auth_method: 'client_secret_basic'
      });

      app.use(
        expressSesssion({
          secret: 'kbrsession',
          resave: false,
          saveUninitialized: true
        })
      );

      app.use(passport.initialize());
      app.use(passport.session());

      const outhStrategy = () => (req, res, next) => {
        passport.use(
          'oidc',
          new Strategy({ client, params: openidCfg }, (tokenSet, done) => {
            const claims = tokenSet.claims();
            console.log('claims was provided successfully!', claims);
            const user = {
              id: claims.sub,
              id_token: tokenSet.id_token,
              claims
            };
            return done(null, user);
          })
        );
        next();
      };

      passport.serializeUser((user, done) => {
        done(null, user);
      });
      passport.deserializeUser((user, done) => {
        done(null, user);
      });

      app.get('/', outhStrategy(), passport.authenticate('oidc'));

      // authentication callback -  this is called successfully
      app.get('/redirect', (req, res, next) => {
        passport.authenticate('oidc', (err, user) => {
          console.log(`got the user ${user.claims.sub}`);
          if (err) {
            console.log(`error occurred ${err}`);
          }
          return res.redirect('https://www.mysite.com/');
        })(req, res, next);
      });

    });
};

However when I try to use the express with the same values(clientid clientsecret etc) Im getting error

app.use(
    auth({
     issuerBaseURL: `${(process.env.NVM_URL)}/.well-known/openid-configuration`
     authorizationParams: {
     response_mode: 'form_post',
    }

I got error that the issuer support only only query of fragment , any idea why?

big-kahuna-burger commented 4 years ago

@astrixj Your issuer discovery document defines this in response_modes_supported field, so unless form_post isn't present in it, it is likely not supported.

astrixj commented 4 years ago

@ big-kahuna-burger - did you see the the I've posted, I use the discover of https://github.com/panva/node-openid-client for the exact same issuer and this works, how do you explain this?

astrixj commented 4 years ago

@ big-kahuna-burger Issuer.discover(${(process.env.NVM_URL)}/.well-known/openid-configuration) .then((criiptoIssuer) => { const client = new criiptoIssuer.Client({ client_id: process.env.NVS_CI, client_secret: process.env.NVM_CS, redirect_uris: [process.env.RDR_URI], token_endpoint_auth_method: 'client_secret_basic' });

big-kahuna-burger commented 4 years ago

@ big-kahuna-burger - did you see the the I've posted, I use the discover of https://github.com/panva/node-openid-client for the exact same issuer and this works, how do you explain this?

I'm not trying to explain it. I'm just saying that your OP discovery document states response_modes_supported and if you are using the one unsupported - it is likely the reason for error you are seeing.

astrixj commented 4 years ago

@ big-kahuna-burger - you dont think that there is maybe different way to use it ? as it doesnt make sense that it work with x library and with the second for the same issuer I got erorr message, maybe it should defined differently ?

panva commented 4 years ago

@astrixj it would be great if you discerned between issues of specific libraries. None of what i'm seeing here is a problem with openid-client. The response mode error isn't coming from this library so why discuss it here? passport, same thing.

panva commented 4 years ago

As far as i can see tho, it "works" with passport for you but it clearly can't be using the response_mode=form_post since your callback is registered for a GET. So it's likely your OP is completely ignoring that parameter, else you'd be getting a POST. The express-openid-connect tells you of this issue since the response modes in discovery don't list form_post.