Configuring the Okta Sign-In Widget to enable partner login to SPA via SAML 2.0 IdP (Google)

We have developed a client web application (Angular Single Page Application) registered as an SPA application in Okta configured with the mandatory settings for an SPA of Implicit flow and OpenID Connect sign on method.

We want to enable Single Sign On to our application for our external customer using the Okta Sign-In Widget (@okta/okta-signin-widget@2.10.0, GitHub - okta/okta-signin-widget: Okta SignIn widget that renders the new login/auth/recovery flows).

Our customer has configured a SAML application in Google and we have configurd the Google SAML application as a SAML 2.0 Identity Provider in our Okta instance and have successfully tested the interaction between Google (Identity Provider) and Okta (Service Provider).

We may soon want to use Identity Provider Discovery (currently an Early Access Feature in Okta) to enable use to support a different Identity Provider for each customer, but we are not ready for this yet operationally and at present we only have one customer ready to use the application so right now we only need to provide access to their users and our internal users.

Q: Is use of a SAML IdP via OpenID Connect a supported scenario for a Single Page Application using the Okta Sign-In Widget, and if so, how do we achieve this, and where is that documented?

I believe that the Okta Sign-In Widget must support this, at least internally, since presumably it forms part of the Identity Provider Discovery feature after the relevant Identity Provider has been discovered.

We have followed the guidance in the OpenID Connect configuration section for the Okta Sign-In Widget (GitHub - okta/okta-signin-widget: Okta SignIn widget that renders the new login/auth/recovery flows), specifying the IdP ID of the SAML 2.0 Identity Provider in Okta, and this all appears to work as expected, with customer users assigned to the SAML application confgured in Google able to sign in and access our application, and although it is strange that we have explicitly specified Google as the provider here since it is integrated with Okta as a SAML 2.0 Identity Provider, everything appears to work as expected:

idps: [{type: 'GOOGLE', id: '0oaaix1twko0jyKik0g4'}]

In our SPA Angular application, we are using the following npm packages as our Okta integration setup:

  • @okta/okta-angular
  • @okta/okta-auth-js
  • @okta/okta-signin-widget

We use the OktaCallbackComponent from the okta-angular SDK which expects the okta-oath-redirect-params cookie and when we tried to use the Okta authorize URL via a custom button this cookie is not set so the flow fails once redirected back to our Application:
https:// <your_okta_url> /oauth2/v1/authorize?idp= <IDP_ID> &client_id= <Client ID> &response_type=id_token&response_mode=fragment&scope=openid&redirect_uri=< redirect_url>

Is the link you are generating in your angular app?

The OktaCallbackComponent is OIDC-compliant, meaning that it needs to validate the nonce/state for security reasons.

I assume that you are also passing state + nonce to your authorization URL. But you need to store these values in a cookie (by default called okta-oauth-redirect-params)

{
  "responseType": ["id_token"],
  "state": "nM8asdzxcaAtFTL",
  "nonce": "xHI73oCFaBSyL6W526NKh3WK",
  "scopes": ["openid", "profile", "email"],
  "urls": {
    "issuer": "https://tom-okta-free.oktapreview.com/oauth2/default",
    "authorizeUrl": "https://tom-okta-free.oktapreview.com/oauth2/default/v1/authorize",
    "userinfoUrl": "https://tom-okta-free.oktapreview.com/oauth2/default/v1/userinfo"
  }
}

Thanks @tom

We generate the link in our Angular application in the format described in Create the Authorization URL and present the link via a custom button in the Okta Signin Widget.

What you’ve presented here looks like it might help.

What is the recommended method for setting the okta-oauth-redirect-params cookie?

Should we set document.cookie directly?
or
Should we be calling getWithRedirect (from token.js in okta-auth-js), which also seems to set two other cookies called okta-oauth-state and okta-oauth-nonce?
or
Something else?

Where is the requirement to populate the okta-oauth-redirect-params cookie to support the OktaCallbackComponent documented?

If it’s not documented, does that mean that using a SAML identity provider with the OktaCallbackComponent is not officially supported?

We want to enable Single Sign On to our application (Angular SPA) for our external customer (who use Google as their identity provider) and restrict access to only the customer’s users (plus some internal users).

At the moment it is OK to support only one customer and their identity provider, and we are not concerned about having a big button that says “Sign in with Google” displayed on the login page.

We have implemented 3 approaches which all appear to work correctly and appear to result in the same thing, ultimately redirecting the browser to the following URL and allowing us to sign in via Google:

https://dev-124007.oktapreview.com/sso/saml2/0oafx918hjPnUSNxA0h7?fromURI=/oauth2/v1/authorize/redirect?okta_key=WTJRjh3DnLgy82aixf3r0LqyUfZCgM5ejb1LlMzoeI4

Approach 1 - Use the idps array

idps: [{ type: 'Google', id: '0oafx918hjPnUSNxA0h7' }],

The Okta Sign-In Widget documentation (https://github.com/okta/okta-signin-widget#openid-connect) creates the impression that is for use only with social identity providers, but as far as we can tell, this works with a SAML2 identity provider, too.

Redirects to:
https://dev-124007.oktapreview.com/sso/saml2/0oafx918hjPnUSNxA0h7?fromURI=/oauth2/v1/authorize/redirect?okta_key=WTJRjh3DnLgy82aixf3r0LqyUfZCgM5ejb1LlMzoeI4

Approach 2 - Use token.getWithRedirect()

customButtons: [
{
  title: 'Login with Google (auth url)',
  click: function() {
       oktaAuth.token.getWithRedirect({
         scopes: [
              'openid',
              'email',
              'profile'
         ],
         responseType: ['id_token', 'token'],
         response_mode: 'fragment',
         token_type: 'Bearer',
         state: '0',
         nonce: '0',
         idp: '0oafx918hjPnUSNxA0h7'
       });
  }
}]

Looking at the getWithRedirect code, we see that it creates 3 cookies:

  • okta-oauth-redirect-params
  • okta-oauth-state
  • okta-oauth-nonce

Redirects to:

https://dev-124007.oktapreview.com/sso/saml2/0oafx918hjPnUSNxA0h7?fromURI=/oauth2/v1/authorize/redirect?okta_key=WTJRjh3DnLgy82aixf3r0LqyUfZCgM5ejb1LlMzoeI4

Approach 3 - Manually create the okta-oauth-redirect-params cookie and manually redirect the browser via window.location.href to the /authorize endpoint

const nonce = uuidv4();
const state = '0';
const authUri = configService.oktaIssuer + '/v1/authorize';
const userinfoUri = configService.oktaIssuer + '/v1/userinfo';
 
document.cookie = 'okta-oauth-redirect-params=' + JSON.stringify({
  responseType: ['id_token', 'token'],
  state: state,
  nonce: nonce,
  scopes: ['openid', 'profile', 'email'],
  urls: {
       issuer: configService.oktaIssuer,
       authorizeUrl: authUri,
       userinfoUrl: userinfoUri
  }
}) + ';path=/';
 
const googleRedirectUri = yuri
  .pathname([authUri])
  .query({
       idp: configService.oktaIdp,
       client_id: configService.oktaClientId,
       response_type: 'id_token token',
       response_mode: 'fragment',
       scope: 'openid profile email',
       redirect_uri: configService.oktaRedirectUri,
       nonce: nonce,
       state: state
  })
  .format();
 
window.location.href = googleRedirectUri;

Redirects initially to:
https://dev-124007.oktapreview.com/oauth2/default/v1/authorize?idp=0oafx918hjPnUSNxA0h7&client_id=0oaftb1guyCmHAzrP0h7&response_type=id_token%20token&response_mode=fragment&scope=openid%20email%20profile&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fimplicit%2Fcallback&nonce=87b5e45d-af85-4cfd-aff2-dc7aef18806b&state=0

And then redirects to:
https://dev-124007.oktapreview.com/sso/saml2/0oafx918hjPnUSNxA0h7?fromURI=/oauth2/v1/authorize/redirect?okta_key=WTJRjh3DnLgy82aixf3r0LqyUfZCgM5ejb1LlMzoeI4

Using this approach, we’ve confirmed that it’s not necessary to create the okta-oauth-state or okta-oauth-nonce cookies.

Issues

Our implementation is based on the following

  • Okta with Google as SAML 2.0 IdP
  • Okta Sign-In Widget
  • OktaCallbackComponent

The approach described here https://developer.okta.com/authentication-guide/saml-login/#create-the-authorization-url does not make any reference to use with the OktaCallbackComponent. The OktaCallbackComponent will fail on callback if the okta-oauth-redirect-params cookie is not present.

@tom, in your previous response you explains that an appropriately-configured okta-oauth-redirect-params cookie is required and show what it should look like, but it is not clear whether or where this information is available in Okta’s public documentation.

Questions

  1. What is Okta’s recommended approach to using the Okta Sign-In Widget and OktaCallbackComponent with a SAML 2.0 IdP?

  2. Do any of our implemented approaches described above match that recommendation?

(Okta seems to be recommending approach 3 above, which seems to us to be basically the same as approach 1 if we don’t care about having no control over the appearance of the login button.)

  1. Where in the publicly available Okta documentation is the description of Okta’s recommended approach to using the Okta Sign-In Widget and OktaCallbackComponent with a SAML 2.0 IdP?

Hello there,

If multiple factors are configured for Okta MFA for any user, which one will be considered?
My client wants us to implement EBS Okta…

  1. SSOGEN

  2. Oracle EBS – Okta Single Sign On Integration

  3. Oracle EBS Siteminder SSO Integration

  4. Oracle EBS and Kerberos Integration

  5. Oracle EBS and SAML IDP Integration for Single Sign On

Any recommendations please?
Thank you,
– Mike.