Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple Client Id and Multiple Issuer URL. #243

Open
maheshwariG opened this issue Feb 12, 2022 · 7 comments
Open

Multiple Client Id and Multiple Issuer URL. #243

maheshwariG opened this issue Feb 12, 2022 · 7 comments

Comments

@maheshwariG
Copy link

Hello team,

we have a requirement of having 2 CTA on home page. Employee Login and partner login.
image.
For Employee Login we have different client Id and issuer url.
For Partner Login we have different client Id and issuer url.
Our application is single page application with react.

Below are the okta library we are using
import { Security } from '@okta/okta-react';
import { OktaAuth, toRelativeUrl } from '@okta/okta-auth-js';

Please help me how handle this in react single page application.

@denysoblohin-okta
Copy link
Contributor

denysoblohin-okta commented Feb 14, 2022

You can try next approach.
Create 2 instances of OktaAuth with different config - one for the Employee app and second one for the Partner app.

const oktaAuth1 = new OktaAuth(config1);
const oktaAuth2 = new OktaAuth(config2);

You need to store tokens in different places, please use different tokenManager.storageKey for this:

const config1 = {
    // clientId, issuer, redirectUri for app1
    tokenManager: {
      storageKey: 'app1',
    },
};
const config2 = {
    // clientId, issuer, redirectUri for app2
    tokenManager: {
      storageKey: 'app2',
    },
};

Display 2 buttons for login that handles onClick accordingly:

oktaAuth1.signInWithRedirect()
 -or-
oktaAuth2.signInWithRedirect()

Use different routes for employee and partner apps.
Wrap routes in separate <Security> components with different oktaAuth prop:

      <Security
        oktaAuth={oktaAuth1}
        onAuthRequired={customAuthHandler1}
        restoreOriginalUri={restoreOriginalUri}
      >
          <Switch>
            <Route path="/app1" component={Home1} />
            <Route path="/app1/login/callback" component={LoginCallback} />
            <SecureRoute path="/app1/profile" component={Profile1} />
          </Switch>
      </Security>

      <Security
        oktaAuth={oktaAuth2}
        onAuthRequired={customAuthHandler2}
        restoreOriginalUri={restoreOriginalUri}
      >
          <Switch>
            <Route path="/app2" component={Home2} />
            <Route path="/app2/login/callback" component={LoginCallback} />
            <SecureRoute path="/app2/profile" component={Profile2} />
          </Switch>
      </Security>

You can also ask in https://devforum.okta.com/ as it's not typical usage of okta-auth-js and okta-react

@maheshwariG
Copy link
Author

maheshwariG commented Feb 14, 2022

Thanks for responding.

We have single app only with single code base And on home page we need to display 2 cta. We do not have two different app. Same app with 2 different okta client I'd and issuer url.

I have one login.jsx file having both the cta and one app.jsx file. Please suggest me how it can be handled.
Thanks

@denysoblohin-okta
Copy link
Contributor

denysoblohin-okta commented Feb 15, 2022

Then you can have 1 <Security> component.
You still need to create 2 OktaAuth instances with different configs:
(You can leave default options for tokenManager and not customize storageKey as I mentioned earlier)

const oktaAuth1 = new OktaAuth(config1); // config for employee
const oktaAuth2 = new OktaAuth(config2); // config for partner

Use them in login button handlers accordingly:

<button onClick={() => oktaAuth1.signInWithRedirect()}>Employee login</button>
<button onClick={() => oktaAuth2.signInWithRedirect()}>Partner login</button>

Please set up 2 different Sign-in redirect URIs in your Okta app configurations.
Eg. https://<your domain>/employee/login/callback and https://<your domain>/partner/login/callback.

You can determine dynamically what OktaAuth instance of two should be passed to <Security> as follows:

const clientIdFromToken = oktaAuth1.tokenManager.getTokensSync()?.accessToken?.claims?.cid;
const oktaAuth = clientIdFromToken === oktaAuth1.options.clientId || window.location.href.includes(oktaAuth1.options.redirectUri) ? oktaAuth1 : oktaAuth2;

Then you can wrap your routes and components in single <Security> component:

      <Security
        oktaAuth={oktaAuth}
        onAuthRequired={customAuthHandler}
        restoreOriginalUri={restoreOriginalUri}
      >
          <Switch>
            <Route path="/" component={Home} />
            <Route path="/employee/login/callback" component={LoginCallback} />
            <Route path="/partner/login/callback" component={LoginCallback} />
            <SecureRoute path="/profile" component={Profile} />
          </Switch>
      </Security>

(Note 2 different routes handled by same LoginCallback component)

@holdtb
Copy link

holdtb commented Jun 30, 2022

@denysoblohin-okta could you explain how this should be setup in the event a single SPA needed to communicate with 2 different authorization servers? The above works fine if you need one or the other, but what if you needed to maintain multiple tokens?

We have API A which is secured by AuthServer 1 and API B which is secured by AuthServer 2. The SPA needs to be able to talk with both APIs and therefore needs two separate tokens.

Am I approaching this totally wrong? It feels like I'm fighting the tool.

@denysoblohin-okta
Copy link
Contributor

okta-react is designed to be provider of one instance of OktaAuth.
If you really need 2 instances of OktaAuth together, please see my first comment about creating two instances of OktaAuth using different tokenManager.storageKey. You can use them in your app without need of okta-react.

Can you explain the need of 2 issuers in your app?

@holdtb
Copy link

holdtb commented Jul 6, 2022

@denysoblohin-okta We have been following the best practices for Authorization Servers here https://developer.okta.com/docs/concepts/api-access-management/#authorization-server

This suggests having one Authorization Server per API product. Our use case now dictates that our SPA now needs to communicate with two separate API's, each behind their own unique Authorization Server. I'm under the impression the SPA will need to obtain and store an access token for each authorization server.

I have been able to use okta-auth-js to obtain the tokens, but unfortunately cannot find a way to continue using okta-react, specifically the LoginCallback component, multiple times. The tokens seem to collide with eachother even after setting tokenManager.storageKey. Is there a way to continue to get the benefits that okta-react provides or does this use case require doing everything by hand with the lower level okta-auth-js package?

@jaredperreault-okta
Copy link
Contributor

jaredperreault-okta commented Jul 6, 2022

okta-react is a wrapper for okta-auth-js and provides a few conveniences for the React ecosystem, like <LoginCallback /> and SecureRoute. It's completely reasonable to use okta-auth-js directly, instead of okta-react if you find that easier. That being said, I think a component structure like this may solve your problem:

<Switch>
  <Route path="/employee">
    <Security oktaAuth={oktaAuth1}>
      <Switch>
         <Route path="/" component={Employee} />
         <Route path="/employee/login/callback" component={LoginCallback} />
       </Switch>
     </Security>
  </Route>
  <Route path="/partner">
    <Security oktaAuth={oktaAuth2}>
      <Switch>
         <Route path="/" component={Partner} />
         <Route path="/partner/login/callback" component={LoginCallback} />
       </Switch>
     </Security>
  </Route>
</Switch>

Utilizing nested routes allows for the oktaAuth instance to be unique for each LoginCallback (it's provided via React context API via the Security component)

However, it may be easier to write your own LoginCallback component that determines which oktaAuth instance to use based on the auth data provided during redirect

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants