Git Product home page Git Product logo

express-openid-connect's People

Contributors

adamjmcgrath avatar audreybudryte2 avatar balazsorban44 avatar bitpatty avatar crew-security avatar damieng avatar davidpatrick avatar dependabot[bot] avatar dmiller9911 avatar evansims avatar evertdespiegeleer avatar ewanharris avatar frederikprijck avatar jamesqquick avatar jbarrus avatar jfromaniello avatar jmacvey avatar joshcanhelp avatar kmannislands avatar lbalmaceda avatar madaster97 avatar matthewbacalakis avatar nholik avatar nicogarcia avatar omermorad avatar panva avatar pelicanmaster avatar snyk-bot avatar twistedstream avatar widcket avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

express-openid-connect's Issues

Inconsistency in Docs for Refresh Tokens

Description

The docs suggest that you can use refresh tokens by requesting the offline_access scope, however this conflicts with the behavior in the source, which suggests that if the response_type is code that the refresh flow will use PKCE.

I don't view this as being as simple as removing the conflicting example from the docs, because the example treats with what I view as a core use-case of this library: providing a refresh token to use from the JS side of your application. There is no obvious way (nor am I confident that it is secure) to pass the PKCE challenge to a client and even if you get the PKCE challenge to the client, auth0 does not provide a clear path to inject the PKCE challenge into a browser client. I'm happy to open up a pull request removing the conflicting API example if it doesn't make sense to include a replacement for the old flow.

Reproduction

You can reproduce this issue by trying to read an accessToken off of the RequestContext when requesting Offline Access from your OIDC client.

Environment

Please provide the following:

  • Library Version: 2.0.0
  • Node: 14.8.0

OPError: expected 200 OK with body but no body was returned

Describe the problem

I am migrating over to express-openid-connect from the auth0 passport flow and I seem to receive this error when trying to hit any of the endpoints (/login /logout etc): OPError: expected 200 OK with body but no body was returned.

Everything worked fine with the Passport flow. If I run my server (node index.js) in Windows, this error occurs when I try to hit any of the endpoints, however in the same environment using Ubuntu with WSL2, it works fine - Ubuntu itself also works fine.

The issue only seems to occur in my Windows environments. I tried this on 2 different computers.

The issue seems to be that nothing is returned when trying to get the .well-known config (error occurs at /openid-client/lib/helpers/process_response.js:48:11 so perhaps this is an openid issue?)

What was the expected behavior?

When hitting any of the provided endpoints like /login, I should be redirected to Universal Login, but instead I get this error.

Reproduction

  • Step 1: Download and run the auth0 express quickstart project in Windows environment
  • Step 2: Try to login

Environment

  • Version 2.1.0
  • Node.js
  • The error occurs in my project and the auth0 express quickstart so I reckon it's Windows related rather than any other modules

Use access token without server-side session

I'm trying to understand whether it's possible to combine this library with a JWT projected API. Use case: I want to use Auth0 roles, and on my Express app provide /login and /login functionality with express-openid-connect, but also protect the page /createbook with the permission create:book of an Auth0 API (books).

Setup:

 authorizationParams: {
 		response_type: "code",
 		audience: "books",
 		scope: "openid profile email access:gp create:book",
 	}

In the documentation, you mention we can use a server-side session storage to store the access_token. However, it should also be possible to store these client side right? I was thinking something like this:

handleCallback: async (req: any, res: any, next: any) => {
		req.identity.claims.access_token = req.openidTokens.access_token;
		next();
	},

We could then use req.openid.user.access_token combined with express-jwt-authz to validate the permissions on the /createbook route, correct?

Is this recommended / safe? And / or would it be enough to store req.openidTokens.scope in the claims?

Change callback URL

Would like the ability to specify my own callback url and not just have it default to "/callback"

Authorization code flow results in "connect ECONNREFUSED 127.0.0.1:443"

Description

Hello, I am currently in the process of testing the upgrade path to 2.0.0 of this library using Auth0 as my oauth provider. After logging in to Auth0, the callback endpoint fails with the following error: BadRequestError: connect ECONNREFUSED 127.0.0.1:443 at /Users/hsostock/code/connect-web/node_modules/express-openid-connect/middleware/auth.js:105:31 at processTicksAndRejections (internal/process/task_queues.js:97:5)

Note: After doing some debugging, it appears that this is the result of an internal call to https://{auth0-domain}/.well-known/oauth-authorization-server returning a 404 Not Found error (which, for some reason, is surfaced as the above connection refused error).

Reproduction

I am using the following configuration in my express app:

const app = express();
app.use(oidc.auth({
  secret: "secret value",
  routes: {
    login: '/auth/login',
    logout: '/auth/logout',
    postLogoutRedirect: '/',
    callback: '/auth/callback',
  },
  session: {
    rolling: false,
    absoluteDuration: 60, // 60 seconds
  },
  authRequired: true,
  auth0Logout: true,
  clientID: "secret value",
  clientSecret: "secret value",
  baseURL: config.webUrl,
  issuerBaseURL: config.auth.issuerBaseURL,

  authorizationParams: {
    scope: 'openid profile email offline_access',
    response_type: 'code',
  },
}));

And occurs consistently (as mentioned) when validating the authorization code returned from Auth0.

Environment

  • Version of this library used: 2.0.0
  • Version of the platform or framework used, if applicable: Express 4.17.1
  • Other relevant versions (language, server software, OS, browser): Node.js 12.13.1 / Typescript / Chrome

Error: no client authentication mechanism provided

After logging in I get no client authentication mechanism provided. I use oidc-provider with the following client:

{
      client_id: "foo",
      client_secret: "bar",
      token_endpoint_auth_method: "client_secret_post",
      redirect_uris: ["http://localhost:3000", "http://localhost:3000/callback"],
      grant_types: ["authorization_code", "refresh_token"],
      response_types: ["code"]
}

This is my auth config:

{
    clientID: "foo",
    clientSecret: "bar",
    authorizationParams: {
      response_type: 'code',
      response_mode: 'form_post',
      scope: 'openid email offline_access'
    }
}

I can manually curl to get the tokens like described here

I would appreciate any pointers.

option sameSite is invalid

Description

I am receiving the following error when using this library in conjunction with the Auth0 guide:

TypeError: option sameSite is invalid
    at Object.serialize (/home/bryce/wslcode/.../node_modules/cookie/index.js:174:15)
    at ServerResponse.res.cookie (/home/bryce/wslcode/.../node_modules/express/lib/response.js:853:36)
    at Object.store (/home/bryce/wslcode/.../node_modules/express-openid-connect/lib/transientHandler.js:32:7)
    at ResponseContext.login (/home/bryce/wslcode/.../node_modules/express-openid-connect/lib/context.js:91:26)
    at processTicksAndRejections (internal/process/task_queues.js:88:5)

I have tried to work out where the error is coming from but can't quite see how it's occurring.

Environment

My config:

const config = {
  required: false,
  auth0Logout: true,
  appSession: {
    secret: process.env.APP_SECRET,
  },
  baseURL: process.env.BASE_URL,
  clientID: process.env.AUTH0_CLIENT_ID,
  issuerBaseURL: process.env.AUTH0_HOST,
};

Please provide the following:

  • Version of this library used: 1.0.1
  • Version of the platform or framework used, if applicable: Node 12

Understanding - JWT

Hey guys !

I am using your lib on my backend app. Everything works fine !
But I wonder how I should implement on my frontend app.

Does the makeTokenSet function generate an access_token which I can use by simply putting it in the header (Authorization: Bearer <access_token>) of my API calls ?

Currently it seems to be directly redirected to openId provider.

openId.auth({
        required:           req => !(req.originalUrl.includes('/checkAuthentication') || req.originalUrl.includes('/login')),
        issuerBaseURL:      config.issuerBaseURL,
        baseURL:            config.baseURL,
        clientID:           config.clientID,
        clientSecret:       config.clientSecret,
        appSessionSecret:   config.appSessionSecret,

        authorizationParams: {
            response_type: 'code',
            scope: 'openid profile email'
        },

        handleCallback: function (req, res, next) {
            // This will store the user identity claims in the session
            req.session.user         = req.openidTokens.claims();
            req.session.openidTokens = req.openidTokens;
            console.log(req.session.openidTokens);
            next();
        },
    })

Profile edit?

I'm pretty clear on how to retrieve user profile info for display in my app, but how do I edit it?

Functionality within the library itself would be ideal, but is there a workaround where I can send users to an auth0 web page to edit their profiles?

Support: spa and backend on different subdomains, but same domain

Is this library recommended for the scenario where spa and backend are on different subdomains?
I am not able to find a way to do the final redirect to a different subdomain (i.e., redirect to subdomain belonging to app with cookie being set)
For now I am using another set of redirect, post the setting of cookies, just to redirect from backend subdomain to app subdomain.
Is this flow recommended?

Enable default connection

Describe the problem you'd like to have solved

I would like to default to a connection, e.g. google-oauth2

Describe the ideal solution

Pass in a configuration option to the middleware similar to auth0-spa-js's loginOptions, e.g. { connection: "google-oauth2" }

Alternatives and current work-arounds

N/A

Additional information, if any

Standard setup, but using a single connection for an application. It would be nice to redirect to the Google account selection page without having to click "Continue with Google".

When will this lib be production ready?

Hello,

The README states:

"This library is currently in Beta status and has not had a complete security review. We do not recommend using this library in production yet"

Do you have an ETA for when this will be ready for production use please?

Thanks,
Dan

V2 cookies are huge

Hi,

Thank you for your work on v2.
In my use case I need to call userinfo and the v2 api makes it really simple. In v1 I have to keep around users' tokenset with express-session for example.

The issue I have is the size of the appSession cookies (plural because they are chunked in several cookies).
image
A bit more than 4k in my case, is it due to my setup? (I guess a tokenset is stored in the cookies which explains the simplified userinfo api). V1 appSession cookies are ~500 bytes.
For each request+response from the browser to the api the cookies are sent as part of the request and updated cookies are sent from the api.
I think I wouldn't have noticed immediately but the default configuration of nginx (used as reverse proxy in front of the api) doesn't let these large headers go through: (due to the cookie size I think)

[error] 27#27: *897 upstream sent too big header while reading response header from upstream, client: 172.18.0.1, server: , request: "POST /api/auth/callback HTTP/1.1", upstream: "http://172.18.0.5:3001/api/auth/callback"

nginx can be configured to allow this using for example:

proxy_buffer_size          128k;
proxy_buffers              4 256k;
proxy_busy_buffers_size    256k;

What do you think about it?
The tokenset has to be stored somewhere but it's not always needed for very simple usecases right?

Type definition of config params conflict with Joi Validation

Describe the problem

installed package have different definition with github repository
่žขๅน•ๆˆชๅœ– 2020-12-14 ไธ‹ๅˆ1 54 09

What was the expected behavior?

should have same index.d.ts with github master branch

Reproduction

  • npm install express-openid-connect
  • check the node_modules
  • see the difference of index.d.ts between installed package and master branch

Environment

express-openid-connect: 2.0.0.
node: v12.19.0
npm: v6.14.8

Authorization code flow

Hey, I'm interested if there is a way for using this lib with the "Authorization Code Flow" ?
And if so, what configuration should I add?

TypeError: "session.transient" is not allowed

According to the SessionConfigParams you should be able to set the transient property like so:

app.use(
  auth({
    session: {
      transient: true,
    },
  })
);

However this throws TypeError: "session.transient" is not allowed.

The correct code is:

app.use(
  auth({
    session: {
      cookie: {
        transient: true,
      },
    },
  })
);

But this is not how it is defined in the interface.

Using version 2.0.0.

Getting race condition while trying to login using auth()

Description

getting race condition, after user is authenticated via auth() and not able to my corresponding landing page.
I am using sequelize store as store property in the expression- session.

Reproduction

This is how my express session looks like:-
const expressSession = session({
resave: false,
saveUninitialized: false,
store: SequelizeStore,
name: "bbb",
secret: "b3c1d6a7-06b2-4c04-99c9-a52994fpad9a",
proxy: true,
cookie: {
httpOnly: true,
sameSite: "lax",
secure: true,
maxAge
}
});

Environment

  • using the latest commit #607f166b5a0276102e786843aaa81c443943932e
  • using nodejs and express.

Fix

Able to fix the issue by adding below code
req.session.save(function () {
res.redirect(returnTo);
});
in requesthandler after config.handleCallback in middleware/auth js.

Not sure if this correct way. Kindly let me know if its a known bug or if there is any plan for the fix

How can I fix Auth0 AggregateError: TypeError: only valid absolute URLs can be requested

I've been trying to configure Auth0 following the quickstart guide and setting up the configurations as per the documentation. But afterwards I can't seem to navigate to any route, even the /login auth0 route without getting the above mentioned error message.

This is my configuration code

export const config = { required: false, auth0Logout: true, appSession: { secret: process.env.AUTH0_CLIENT_SECRET }, baseURL: 'http://localhost:3001', clientID: process.env.AUTH0_CLIENT_ID, issuerBaseURL: process.env.AUTH0_DOMAIN };

The app using Auth0

`import express from 'express';
import { auth, requiresAuth } from 'express-openid-connect';

import { config } from './controllers/authController';

const app = express();

app.use(express.json());

app.use(auth(config));

// req.isAuthenticated is provided from the auth router
app.get('/', (req, res) => {
res.send(req.isAuthenticated() ? 'Logged in' : 'Logged out');
});

app.get('/profile', requiresAuth(), (req, res) => {
res.send(JSON.stringify(req.openid.user));
});`

the error message i keep getting

AggregateError: TypeError: only valid absolute URLs can be requested at module.exports (C:/Users/Paul Nisiro/Documents/Projects/Node/farmrail/src/services/user_api/node_modules/openid-client/lib/helpers/is_absolute_url.js:10:11)

Not able to get API responses using Postman

Description

I have this module installed in my Express app, and while it seems to work perfectly fine when attempting to make a GET request to a protected endpoint in the browser, making the same request in postman results in this response being returned regardless of what protected endpoint I try to hit:

<html>

<head>
	<title>Submit This Form</title>
</head>

<body onload="javascript:document.forms[0].submit()">
	<form method="post" action="http://localhost:3000/callback">
		<input type="hidden" name="id_token" value="eyJhbGciOiJSUzI1NiIsInR5cCI6Ikp..."/><input type="hidden" name="state" value="eyJyZXR1cm5..."/></form>
</body>

</html>

(Tokens redacted of course).

Reproduction

I have set up Postman according to this guide and I am able to successfully log in and get a bearer token using it
https://auth0.com/blog/manage-a-collection-of-secure-api-endpoints-with-postman/

I then make a request to a protected endpoint that ought to return a simple JSON object, but instead get the above HTML with a status code of 200

Environment

Node 10.22.0
Express 4.17.1
express-openid-connect 2.0.0
Windows 10
Postman 7.34.0

JWEDecryptionFailed

Description

I am using appSession. After successful login, if the server's APP_SESSION_SECRET is changed, library throws a 500 error with JWEDecryptionFailed.

JWEDecryptionFailed: decryption operation failed
     at decrypt (/opt/app/node_modules/jose/lib/jwa/aes_gcm.js:42:11)
     at decrypt (/opt/app/node_modules/jose/lib/jwa/index.js:86:32)
     at jweDecrypt (/opt/app/node_modules/jose/lib/jwe/decrypt.js:165:21)
     at decrypt (/opt/app/node_modules/express-openid-connect/lib/appSession.js:41:16)
     at /opt/app/node_modules/express-openid-connect/lib/appSession.js:81:50
     at Layer.handle [as handle_request] (/opt/app/node_modules/express/lib/router/layer.js:95:5)
     at trim_prefix (/opt/app/node_modules/express/lib/router/index.js:317:13)
     at /opt/app/node_modules/express/lib/router/index.js:284:7
     at Function.process_params (/opt/app/node_modules/express/lib/router/index.js:335:12)
     at next (/opt/app/node_modules/express/lib/router/index.js:275:10)

This is a recoverable error. The library should behave as if the cookie was not in request and prompt the user to login. This should not be fatal.

Reproduction

Login and then manually modify the appSession cookie to break the AES-GCM decryption.

Environment

Please provide the following:

  • Version 1.0.2

state mismatch error

State mismatch

I'm having this error on my second attempt of login. After my token expired (24h), the APP redirects my user to the login screen (another service) and when it makes a successful login, it redirect my user to my APP giving this kind of errors:

  1. BadRequestError: state mismatch, expected eyJyZXR1cm5UbyI6Ii9yb2JvdHMudHh0In0, got: eyJyZXR1cm5UbyI6Ii8ifQ
  2. BadRequestError: checks.state argument is missing at callbackStack

Sometimes is error 1 or 2.

But despite this error, if the user goes to the home page he sees that he is logged in and he can starts use the APP.

This error gives a bad user experience.

What was the expected behavior?

Avoid the error page on callback page.

Reproduction

We are using Node JS with ** Express 4.17.1 **, everything works well except for the lines discussed above.

It seems that the issue is reproduced by transientHandler.js, exactly on the next lines:

  getOnce(key, req, res) {
    if (!req[COOKIES]) {
      return undefined;
    }

    let value = getCookieValue(key, req[COOKIES][key], this.keyStore);

    this.deleteCookie(key, res);

    if (this.legacySameSiteCookie) {
      const fallbackKey = `_${key}`;
      if (!value) {
        value = getCookieValue(
          fallbackKey,
          req[COOKIES][fallbackKey],
          this.keyStore
        );
      }
      this.deleteCookie(fallbackKey, res);
    }

    return value;
  }

The value comes undefined and for that reason the APP makes an exception related to state mismatch.

image

Environment

Our OIDC configuration

module.exports = (app) => {
    app.use(
        auth({
            issuerBaseURL: process.env.JZ_AUTH_AUTHORITY,
            baseURL: process.env.JZ_BASE_URL,
            clientID: process.env.JZ_AUTH_CLIENT_ID,
            clientSecret: process.env.JZ_AUTH_CLIENT_SECRET,

            // cookie
            secret: "xxxxxxxxxxxxxxxxxxxxxxx",
            session: {
                name: "JZ_SC_SESSION",
                rolling: false,
                // 20 hours
                absoluteDuration: 20 * 60 * 60,
                cookie: {
                    // ignore https
                    secure: false
                }
            },

            // authorization params given by identity server
            authorizationParams: {
                response_type: "code",
                response_mode: "form_post",
                scope: "openid email phone profile juntoz jz-public jz-core",
                audience: process.env.JZ_AUTH_AUTHORITY,
                state: "sitecentral"
            },

            // logout the user from identity server
            idpLogout: true
        })
    );
}
  • "express": "^4.17.1",
  • "express-openid-connect": "^2.0.0

Login flow in two tabs at the same time results in state mismatch error

Description

Two browser tabs going through a login process at the same time can result in a state mismatch error.

Reproduction

  1. Open your application in tab 1 and be redirected to the identity provider
  2. Open your application in tab 2 and be redirected to the identity provider
  3. Attempt to finish login process in tab 1

Actual result: A state mismatch error
Expected result: A successful login

Further Details

It appears that this middleware stores the nonce and state in a cookie, which when shared across tabs (or even across requests), invalidates previous login attempts because the previous values are overwritten. We also saw a similar issue where asset requests to our app were triggering the auth flow (this was due to a misconfiguration on our part) and invalidating the current login flow since new nonces/state were issued.

Potentially related issues:
aspnet/Security#179

Using "response_type: id_token token" does not populate req.openid.user correctly(?)

Description

I have the following Express setup:

//...
express()
  .use(auth({
    baseURL: '...',
    required: false,
    idpLogout: true,
    issuerBaseURL: '...',
    clientID: 'orderpages-client',
    authorizationParams: {
      response_type: 'id_token token',
      response_mode: 'form_post',
      scope: [
        'openid',
        'profile',
        'email',
        'address',
        'phone',
        'company_roles',
        'company_profile',
        'company_extended_profile',
        // APIs
        'customer-manager-api',
        'referral-manager-api',
        'order-pages-api',
      ].join(' ')
    }
  }))
.get('/user', requiresAuth(), (req, res) => res.json(req.openid.user))
//...

The last three of the scope are referring to API endpoints, which are called from the front-end application.

Reproduction

The idea is the following:
A React app served from the Express server, using express-openid-connect and a custom IdP for auth.

The user logs in, and after that they can fetch their info through a /user endpoint.
This should ideally contain all the information like openid, profile, email, address, etc. as given in scope, as well as an access_token, that can be later used to make authenticated requests to the APIs also defined in scope.

The user object though does not contain the required fields, if token is present in response_type, which also breaks if scope contains any of the APIs.
image

When removing token, and the APIs from scope, the user object looks fine, containing all the required fields

Environment

  • Version of this library used: latest
  • Version of the platform or framework used, if applicable: Node 12
  • Other relevant versions (language, server software, OS, browser): Linux, Chrome
  • Other modules/plugins/libraries that might be involved: Custom Identity Provider

no valid key found

I'm using

  authorizationParams: {
    response_type: 'code',
    response_mode: 'query',
    scope: 'openid email'
  }

But when returned to the /callback endpoint, the user receives BadRequestError: no valid key found.

Turning on debugging doesn't reveal anything useful. Site output shows:

BadRequestError: no valid key found
    at router.(anonymous function) (/Users/jt/Projects/oidc-test-client/node_modules/express-openid-connect/middleware/auth.js:123:27)
    at process._tickCallback (internal/process/next_tick.js:68:7)

I expect this is to do with token verification and the keystore required by openid-client. How is this configured?

Typescript Definiton SessionConfigParams

Description

Typescript Definition for SessionConfigParams is outdated.

Reproduction

I've tried to set following:

  session: {
    secure: true,
  },

Instead the following works:

  session: {
    cookie: {
      secure: secureCookies,
    },
  },

Environment

  • Version of this library used: Current

Getting bad request error on login: BadRequestError: checks.state argument is missing

Describe the problem

Login callback returns Bad Request error after a successful login. Exception from server side:

BadRequestError: checks.state argument is missing
at callbackStack (/.../node_modules/express-openid-connect/middleware/auth.js:105:31)

What was the expected behavior?

Successful login callback and redirect to the set URL.

Reproduction

  1. using Firefox browser 84.0.1 (64-bit)
  2. login to Auth0 using email account (not social account like google)
  3. open another private browser window (or another tab in the same window)
  4. login to the same email account
  5. at the end of the login, the callback returns Bad Request error

auth0Config:
"auth0Config": { "authRequired": false, "auth0Logout": true, "secret": "...", "baseURL": "https://www.joyridesclub.com", "routes": {"postLogoutRedirect": "https://www.joyridesclub.com/loggedout"}, "clientID": "...", "issuerBaseURL": "..." }

Environment

Node/Express web server
"express-openid-connect": "^2.1.0",

issuer form response_mode: 'form_post'

Hello,

we use the auth config which works with other library

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

while running it we got an error, that the issuer supporting only query of fragment
but not, we have old applications which works with the exact same issuer and we configure the issueBaseURL exactly the same and the response_mode is
form_post, why we are getting this error,is it known issue ? please explain how to proceed.

Rewrite tests

Describe the problem you'd like to have solved

I propose a change to how tests are written after the discussion here: #40 (comment)

Describe the ideal solution

As mentioned, I would use the concept Avoid Nesting when you're Testing, in addition to avoid writing repetitive configs by gathering them on top of each file (or another centralized place like mockData.js or something similar), and create a setup***() function for tests in a single test suite (file).

Reducing the number of nested describe() blocks would also improve readability, by flattening out the test suite. This would be much easier to achieve with the above mentioned setup***() functions.

These are not BREAKING CHANGES ๐Ÿ’ฅ, as it only touches on the testing part. Though, it must be done carefully, so everything that is tested already is migrated first, and then maybe try to think about adding more tests.

Additional context

I have mainly used Jest ๐Ÿƒ for testing, and after working on the logout.test.js tests, I would much prefer to do that here as well. Mocha โ˜• felt a bit cumbersome, and the outputs were not always easily readable IN MY OPINION.

  • If I get green light at work, I may have a bit more time on my hands to work on this then doing it in my free-time. โœ” Green light

Dynamic Client Authentication

Describe the problem you'd like to have solved

I'm trying to develop against an OIDC provider where for a single issuer I may use several different sets of client authentication, even for a single client ID.

Currently, if I startup a single instance of express-openid-connect, I can only assign a single client secret. I would like to be able to dynamically "route" what client authentication I use based on the parameters of the "/login" request.

Describe the ideal solution

Expose client authentication as part of the LoginOptions interface, that way we can dynamically assign the client authentication credentials based on the request itself. Specifically, the /login request to my server will expect a query string param indicating what "instance" to route to and what client authentication to use at the token endpoint for that request.

For this use case, we know precisely what authentication to use by the time the "/login" request comes in.

I think it's a fair assumption that "Dynamic Client Credentials" will only depend on the "/login" request, and that we don't need to do anything fancy like a dynamic function at the "/callback" endpoint.

The challenging bit may be securing the authentication credentials used. For each login flow, we shouldn't be independently storing the client secret in the request's session, as this seems like a security risk. Maybe assigning a key or indicator to the request, and having a sort of key map built into the config would be best.

For instance, lets say that on my "/login" request I can receive a query string param called "issuer" that I will use to route my application. This parameter could have values of "issuer_1" or "issuer_2" which correspond to client secrets "secret_1" and "secret_2" respectively.

In my auth config, I could now include a "clientSecretMap" JSON object containing all of my client secrets keyed to the "issuer"

const config = {
  // Other config...
  clientSecretMap: {
    "issuer_1": "secret_1",
    "issuer_2": "secret_2"
  }
};

Then, within a new parameter on the login request, we could dynamically "route" to any of these pre-configured keys based on the login request itself, rather than re-caching a dynamically generated secret in the requests session.

router.get('/launch', function(req, res, next) {
  res.oidc.login({
    // Other config ...
    clientSecretKeyMap: req.query.issuer
  });
})

If an application tried to route to an issuer that wasn't in the key-map, the request should fail rather than sending a null client secret. This map should be just smart enough so that the developer doesn't need to "double-check" the issuer before attempting to pass the key in.

I don't think we should allow for both a static clientSecret and a key map in the same config. Developers should choose one or the other, and if needed include a default key in their map that they can route to as needed.

Alternatives and current work-arounds

I could spin up several instances of the application with duplicate config (other than the client credentials).

The thing is, this significantly increases startup time, and all of the startup middlewares would be independently calling to the same OIDC metadata endpoint.

I'm also not 100% on how managing several sets of this middleware in one process would work.

Set the redirect uri dynamically

Describe the problem you'd like to have solved

Current dev environment is...

my-dev-domain.com -> (30x redirect) -> some-dynamic-tunnel.ngrok.io

Given this setup, auth will not work because the configured callback domain (my-dev-domain.com in this case) cookies will not be set because of the 30x redirect that is happening above. Changing the callback domain manually won't help because the tunnel is dynamic and that would break a smooth workflow. The whole point of the setup above is to have a static redirect and smooth out the workflow.

Describe the ideal solution

Ideal solution is to configure the redirect uri to match the referrer, thus the cookies will be set on the tunnel address and all is well in the world.

The following commit to my fork works nicely. Auth0 allows wildcard callbacks and it's working excellently.
june07@667b766

The referrerRedirect option by default would have zero effect.

`id_token code` not supported

The following example generates an error saying that id_token code is not supported. Then, I found out that code id_token is what the library (or something else?) is expecting. Is this by design? Or room for improvement?

app.use(eoc.routes({
  issuer_base_url: process.env.AUTH0_DOMAIN,
  client_id: process.env.AUTH0_CLIENT_ID,
  client_secret: process.env.AUTH0_CLIENT_SECRET,
  base_url: appUrl,
  authorizationParams: {
    response_type: 'id_token code',
  },
}));

GetUser

Thank you for the great package.

How to use the getuser in the auth and refresh token . Please guide on this.

We tried this, but not working
app.use(auth({ getUser: (tokenSet) => {
console.log(tokenSet);
},
authorizationParams: { scope: "openid profile full", response_type: "code" }

}));

Support JWT-Based Client Authentication

Describe the problem you'd like to have solved

I am trying to develop against on OIDC provider that only accepts private_key_jwt client authentication, and am unable to with this middleware.

Describe the ideal solution

Add support for private_key_jwt and client_secret_jwt client authentication methods. In the startup config, a field for a JWKs set would be best, where the specific KID to be used on a request could be routed on login (similar to solution in this issue). If the JWK only had one key, then that could be used as a default client authentication value.

Alternatives and current work-arounds

None for this library. I'm currently trying to wrap express around openid-client myself, but that loses a lot of the awesome functionality in this lib :)

Support for WebSocket upgrade authentication

Describe the problem you'd like to have solved

Assuming a user has already logged in via the usual means, it would be handy to be able to use the session cookie to authenticate users during the WebSocket upgrade request (assuming websocket server and http server running on the same domain).

I don't think it's currently easy/possible to use this library to implement an authenticate function suitable for the upgrade request as in this code sample.

I'm relatively new to how openid connect works so I guess there could be some technical reason as to why this isn't possible.

Describe the ideal solution

An authenticate function with a matching signature or something you could just import or have optionally returned from calling auth (or a similar function) would be ideal. Failing that, the ability to call a function to validate the session cookie and get the oidc/oidc.user objects/profile would probably do.

Alternatives and current work-arounds

Hacking it together (not yet working)

I browsed through the code and started hacking something together which returned the appSession instance created here in an object along with the router.

I also added an if here to cope with a null response object.

My plan was then to call it like this

import { get as getConfig } from 'express-openid-connect/lib/config';
import { RequestContext } from 'express-openid-connect/lib/context';
import { auth, requiresAuth } from 'express-openid-connect';

const authConfig = getConfig(authParams);
const { router, appSessionMiddleware } = (auth(authParams) as any);
// ...
server.on('upgrade', async (req, socket, head) => {
  appSessionMiddleware(req, null, async req => {
    try {
      const oidc = new RequestContext(authConfig, req, null, () => console.log("next was called"))
      const userInfo = await oidc.fetchUserInfo();
      console.log("Got user info %s", userInfo);
    } catch(e) {
      console.log("Got err %s", e);
    }
  }
}

I then hit a problem with this line and remembered that the req object express gives you is different to the req/socket object you get from http, however it's still possible to get the cookie values from signedCookies, I think it just has a slightly different interface.

PassportJS and Cookie Parser

I originally had a setup with passportjs and cookie-parser but that involved storing the sessions in a database and I was having trouble with data races which is what prompted me to switch to express-openid-connect.

Ticket Based Authentication

I guess it would also be possible to have an ordinary authenticated api route to request a 'ticket' and implement a ticket based authentication system as described here. However I'm not sure quite what should go into a ticket and how large it would need to be to be reasonably secure.

Additional context

With a bit more hacking on the code and some guidance I'm fairly confident I could put together a PR for this feature.
However it would be nice to be sure that I haven't missed something fundamental and this idea isn't totally flawed.

Using auth.handleCallback() appears to cause infinite redirect

Description

One of my applications that depends on express-openid-connect needs access to JWT in the routes. Prior to v.0.6.0, JWT was available in req.openid.tokens.id_token.

After upgrading to v.0.6.0 I have attempted to follow the instructions (in point numbers 4 and 5) at https://github.com/auth0/express-openid-connect/blob/master/EXAMPLES.md. But what I am seeing is when I add a auth.handleCallback() property, my RP becomes stuck in an infinite loop of requests between it and its OP.

In the RP log I see:

  1. "GET /" - client requesting the RP resource
  2. Debugging information (console logging, as in my code in the Reproduction section below)
  3. "POST /path/to/my/RP/redirectUriPath"

.. this pattern repeats over and over until I close the client web browser. If I remove the auth.handleCallback() property, then authentication completes normally. But then I don't have access to the JWT.

Reproduction

Simplified Express (app.js) code, which still produces the issue:

const sessionOpts = {
  secret: env.getSessionSecret(),
};

const authOpts = {
  issuerBaseURL: env.getOidcOpUri(),
  baseURL: env.getOidcRpUri(),
  clientID: env.getOidcClientId(),
  redirectUriPath: env.getOidcRedirectPath(),
  required: true,
  authorizationParams: {
    response_type: 'id_token',
    response_mode: 'form_post',
    scope: 'openid profile email',
  },
  appSessionSecret: false,
  handleCallback: async function(req, res, next) {
    req.session.oidcTokens = req.openidTokens;
    console.log('In the callback-handler');
    console.dir(req.openidTokens);
    next();
  },
};

// Set up session, body parser, authn
app.use(session(sessionOpts));
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json({strict: false}));
app.use(auth(authOpts));

Environment

  • express-openid-connect 0.6.0
  • express 4.17.1
  • express-session 1.17.0

CORS error on accessing cross domain API of express apps

Description

Allowing access to API (cross-domain) and treating the API request as authenticated and avoid redirecting to authorize/ end point

Reproduction

Hit localhost/app/app1 where internally front end of app1 is sending a request to localhost:8022/app/app1/fetch . Below is the code
Gateway App which is front facing app for all of the sub apps ( app0,app1,app2) - http://localhost/app/
App1 URL - http://localhost/app/app1/
API URL - http://localhost:8022/app/app1/fetch

Gateway App Code

`
const express = require('express');
const app = express();

//per application entry

const app0 = require("./app_folder1");
const app1 = require("./app_folder2");
const app2 = require("./app_folder3");
const app3 = require("./app_folder4");

require('dotenv').config();

const {
auth , requiresAuth
} = require('express-openid-connect');

app.use(auth({
required:function (req) {
console.log(req.isAuthenticated());
if (req.headers['x-requested-with'] === 'XMLHttpRequest')
return true;
else
return false;
},
issuerBaseURL: process.env.ISSUER_BASE_URL,
baseURL: process.env.BASE_URL,
clientID: process.env.CLIENT_ID,
clientSecret: process.env.APP_SESSION_SECRET,
redirectUriPath:'/app/callback',
authorizationParams: {
response_type: 'code',
scope: 'openid profile email',
custom_param: "custom-value",
response_mode: 'form_post',
},
idTokenAlg: 'RS256',
appSession: {
secret: process.env.APP_SESSION_SECRET,
duration: 3600
},
handleCallback: async function (req, res, next) {
req.appSession = req.appSession || {};
try {
next();
} catch (e) {
next(e);
}
}
}));

// Add headers
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*'); // for reverse proxy
next();
});

//per application path mapping

app.use('/app/app0/', app0);
app.use('/app/app1/', app1);
app.use('/app/app2/', app2);
app.use('/app/app3/', app3);
app.listen(8022);
`

Libraries and Dependencies

NodeJS - 11
express-openid-connect - 1.0.2
express - 4.16.3
Browser - Google Chrome
Identity provider - Okta

Logout function and tokens

In the logout function, req.openid.tokens is used but this variable does not exist:
https://github.com/auth0/express-openid-connect/blob/master/lib/context.js#L137

It would be nice to have a function that returns the tokens (similar to the getUser function). And by default, save these tokens in cookies (http-only), but by having the function, the user will be able to use another method to save tokens (such as express-sessions).

At the same time the function would be very useful for the user to have the tokens, and use for example in calls to the api.

Make redirect optional for login, logout

Describe the problem you'd like to have solved

I want to call the login endpoint via AJAX request and simply get the redirect URL in the response.
I've not found a way to change this behavior without modifying the library source code.

Describe the ideal solution

So the possible solution is to have two methods: login, loginWithRedirect in the RequestContext class.

Microservices

Hey, I wonder how to use this lib with a microservices architecture.

In my previous issue you added the link below(by the way thank you for the answer there and sorry for my inactivity)
So about the link I saw that the node server renders the html pages but what should I do if I just use the node server for RESP api?
(I would like to use the Authentication Code flow so the 'login' part would be from the frontend and the 'code to token' exchange would be from the backend)

https://github.com/auth0-samples/auth0-express-webapp-sample/tree/master/01-Login

Thank you

How to provide returnUrl on /logout

I have the following express implementation:

// ...
express()
  .use(auth({
      required: false,
      idpLogout: true,
   }))
//...

I use the default /login, /logout, /callback routes.
idpLogout is set to true, because I want the user to be logged out from the Identity Provider as well. My problem is, that after logging out, they stay on the Identity Provider.

How can I pass a returnUrl, so the user comes back to the site?
I tried putting this at the frontend <a href="/logout?returnUrl=http://example.com">Log out</a>, but it did not help.

How to link directly to Sign-Up

Describe the problem you'd like to have solved

I'm trying to figure out how to create a route that will take people straight to Sign up (example: /register)

Describe the ideal solution

I tried this:

app.get('/register', (req, res) => {
  res.openid.login({returnTo: '/', initialScreen: 'signUp'});
})  

But that just took them straight to login like usual.

How can I send them to login page with Sign-Up Pre-selected?

Getting error when running tests

Description

When running tests, a particular test fails randomly.

image

Reproduction

  1. run npm test
  2. wait for the error to randomly appear ๐Ÿ™ƒ

Environment

Please provide the following:

  • Version of this library used: 0.5.0
  • Version of the platform or framework used, if applicable: Node 12.12.0
  • Other relevant versions (language, server software, OS, browser): Ubuntu 19.10
  • Other modules/plugins/libraries that might be involved: -

Document audience param

Describe the problem you'd like to have solved

Multiple places in the documentation refer to an audience param (examples here and here). However, it's not clear to me what the value should be for audience.

Describe the ideal solution

Add audience to the API documentation and provide more specific examples than "https://your-api-identifier".

Alternatives and current work-arounds

None identified. I'm still Googling trying to figure out the correct value for audience.

Additional context

I used the beta experimental Quickstart for Node to set up Auth0 in my app.

BadRequestError: checks.state argument is missing

Description

Sometimes while testing this I get:

BadRequestError: checks.state argument is missing
    at <folder>/node_modules/express-openid-connect/middleware/auth.js:105:31
    at processTicksAndRejections (internal/process/task_queues.js:97:5)

This happens randomly after logging in.

Reproduction

It happens especially often at the first login, but sometimes just randomly after logging in. My code:

require('dotenv').config()
const express = require('express')
const app = express()
const { auth } = require('express-openid-connect')
const config = {
  authRequired: false,
  auth0Logout: true,
  issuerBaseURL: process.env.ISSUER_BASE_URL,
  baseURL: process.env.BASE_URL,
  clientID: process.env.CLIENT_ID,
  secret: process.env.SECRET,
}
app.use(auth(config))
app.get('/', (req, res) => {
  res.send(req.oidc.isAuthenticated() ? 'Logged in. Welcome!' : 'Logged out. <a href="/login">Login?</a>')
})
app.listen(3000)

Environment

  • Version of this library used: 2.0.0
  • Version of the platform or framework used, if applicable: Express version 4.17.1
  • Other relevant versions (language, server software, OS, browser): Node.js version 12.18.4 installed with nvm, macOS 10.15.6, Chrome 85.0.4183.121
  • Other modules/plugins/libraries that might be involved: dotenv version 8.2.0

Removal of automatic refresh

What was the rationale behind removing the automatic refresh feature? Is there a recommended approach to automatically refreshing sessions if the access-token has expired?

Thanks in advance!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.