Open ShayElkana opened 4 years ago
@ShayElkana The appBaseUrl
is used for constructing the loginRedirectUrl
and the logoutRedirectUrl
. These URLs are not used by our module directly but are passed to the
openid-client module which handles the OIDC redirect flow. We are also using the
passport module to provide session. Although we do not support this scenario directly, I think with some clever coding you could adapt these modules to use a url from the header to select a redirect uri from a known list. Keep in mind that all redirect uris will need to be whitelisted with Okta, so there is some limit to how dynamic it can be.
Also worth thinking about for this scenario is that the OIDC flow is not stateless, a state & nonce value are saved before redirect and validated upon return, so the servers will need to share a session memory or have some other way of pinning a user to a specific server.
We appreciate the request for enhancement. If you have some specific ideas about how to implement this using our middleware, you are welcome to fork the project and we will be happy to consider a pull request.
I found a workaround that allow you to initialize the middleware multiple times for different domain. basicaly, the problem is that the library has a singelton nature. I force it to load different instance by doing:
delete require.cache[require.resolve('passport')]
delete require.cache[require.resolve('@okta/oidc-middleware/src/oidcUtil.js')]
delete require.cache[require.resolve('@okta/oidc-middleware/src/connectUtil.js')]
delete require.cache[require.resolve('@okta/oidc-middleware/src/ExpressOIDC.js')]
delete require.cache[require.resolve('@okta/oidc-middleware')]
const { ExpressOIDC } = require('@okta/oidc-middleware')
I do that before each initialization.
for example:
const baseMiddlwwareOptions = {
issuer: `${OKTA_BASE_URL}/oauth2/default`,
client_id: OKTA_CLIENT_ID,
client_secret: OKTA_CLIENT_SECRET,
scope: 'openid profile'
}
const lib1 = require('@okta/oidc-middleware')
const oidcMiddlewareOptions1 = {
...baseMiddlwwareOptions,
appBaseUrl: 'https://first.com',
routes: {
login: { path: '/first-login' },
loginCallback: { path: '/first-authorization-code/callback' }
}
}
const oidcMiddleware1 = new lib1.ExpressOIDC(oidcMiddlewareOptions1)
expressApp.use(oidcMiddleware1.router)
delete require.cache[require.resolve('passport')]
delete require.cache[require.resolve('@okta/oidc-middleware/src/oidcUtil.js')]
delete require.cache[require.resolve('@okta/oidc-middleware/src/connectUtil.js')]
delete require.cache[require.resolve('@okta/oidc-middleware/src/ExpressOIDC.js')]
delete require.cache[require.resolve('@okta/oidc-middleware')]
const lib2 = require('@okta/oidc-middleware')
const oidcMiddlewareOptions2 = {
...baseMiddlwwareOptions,
appBaseUrl: 'https://second.com',
routes: {
login: { path: '/second-login' },
loginCallback: { path: '/second-authorization-code/callback' }
}
}
const oidcMiddleware2 = new lib2.ExpressOIDC(oidcMiddlewareOptions2)
expressApp.use(oidcMiddleware2.router)
what do you think?
@LiranBri - That will allow multiple instances of the middleware, but have you confirmed that these instances aren't maintaining different fragmented sessions that will lead to a user having problems when follow-up requests end on different server instances?
@swiftone why would it happen?
If the backend stores the user's context data in memory session on the backend side, I expect each instance to store its own data, even if they would share the same session
object.
It may happen if the same user would use different domains, and the key in the session object is the user id.. but the idea, at least in my design, is that each user may use a specific domain, but should not use another
but I didn't check it because in my case, the session is stored on the client's cookie and not backend side memory (which I believe is the best practice, to keep the backend stateless).
I see that there is an optional, undocumented, option sessionKey
which controls the key in the session object. so it can be used to isolate each instance.
by default, it takes just the issuer
, which is indeed shared between all instances.
it should be pretty simple to create a dedicated sessionKey
for each instance, compound of issuer
+ appBaseUrl
(or routes.login.path
)
@swiftone @aarongranick-okta
is there a reason the option sessionKey
not documented?
I can create a PR for documentation
I have a need for this to be able to white label a single instance website for use with multiple hosts/domains.
related to okta/okta-oidc-js#497
Internal ref: OKTA-291513
is there any update on this? I saw there was a PR out that claimed to remediate this issue from 2019 that was never reviewed.
https://github.com/okta/okta-oidc-js/pull/498
At first glance this seems ok!
@peterhriser I will take a look and see if we can move this PR forward
The workaround of deleting the require cache is not an option when using es modules since es modules are immutable. This is a major blocker.
Has anyone found a workaround/solution for ES Modules? I need to support multiple IdPs, if this library does not support this any other library recommendations that do support multiple IdPs?
I'm submitting this issue for the package(s):
I'm submitting a:
Current behavior
Today we have to declare at app init what is the app appBaseUrl as you can see below: const oidc = new ExpressOIDC({ issuer: 'https://{yourOktaDomain}/oauth2/default', client_id: '{clientId}', client_secret: '{clientSecret}', appBaseUrl: '{appBaseUrl}', scope: 'openid profile' }); Which limits us to deploy each instance of our application under a single domain.
Expected behavior
We wish to deploy our system into a set of servers under a single load balancer, but we are going to have a few subdomains which all of them are pointing to the same load balancer and from there to the same web application, please see the sketch below:
we wish that the appBaseUrl will be optional since okta middleware can take the appBaseUrl from the host header on each HTTP request, and then it will be possible to use the same app under more than one appBaseUrl