Tableau Server OpenID SSO integration with Azure AD B2C seamless iframe authentication

Contrary to popular belief, it is possible to achieve seamless SSO iframe embedding with Azure AD B2C and OpenID Connect.

This step-by-step tutorial will help you achieve the following:

  • Configure Azure AD B2C as an Identity Provider (IdP) for Tableau, by leveraging OIDC auth protocol. (Note: if you wish to use SAML instead, have a look at this excellent post by Andrija)
  • Enable seamless iframe SSO embedding (NB: Microsoft is commonly known to block any sort of in-frame authentication flows, but in reality with just a couple of lines of code you can define a custom CSP policy that will allow for such for your trusted domains)
  • Learn the tools of the trade on how troubleshoot integration issues between Tableau and OIDC IdPs

Demo of the finished solution

A super simple SPA application that authenticates the user against Azure AD B2c using OpenID. Once the user is authenticated in the portal, the Tableau Authentication happens transparently within the iframe (SSO):

As you can see, both Tableau and the SPA Portal leverage the same OpenID IdP (Azure AD B2c).

If you are curious, the demo was built with this sample app, which uses MSAL.js 2.x library from Microsoft to integrate the OpenID authorization flow with PCKE. I’ve tweaked it a bit to add the Tableau embed code based on this sample. You don’t need to set up the SPA to follow this blog post, as it’s just an arbitrary example of embedded portal, so feel free to ignore it.


  1. Tableau Server installed and running on HTTPS. You can even use a self-signed SSL certificate (check my other post if you need help to create it). Take note of your <your-tableau-server-hostname> (e.g.
  2. Admin access to both Tableau Server GUI and its VM/container
  3. Tableau Log Viewer installed (for troubleshooting config issues)
  4. Create an Azure AD B2C tenant that is linked to your Azure subscription and take note of the tenant-name

Azure AD B2C config

1. Create a consumer user in B2C for testing the auth flows. I’m using email as a claim to match the Azure user with Tableau’s username, but you may use something else.

2. Register a web application and call it Tableau App. For the redirect URI, use the following: https://<your-tableau-server-hostname>/vizportal/api/web/v1/auth/openIdLogin

Take note of the new Application (client) ID: <B2c-Tableau-App-ClientID>

3. On the Tableau App, go to Certificates & secrets and create a new client secret. Take note of the app secret value <B2c-Tableau-App-Secret>

4. On the Tableau App, go to Expose API and at the top, click SET Application ID URI:

5. Then add a scope (this could be Read, Update Parameter, etc). We’ll use Read

6. Then go to API Permissions, and add the API exposed above and Grant admin consent. You should also have granted consent to Ms Graph’s openid permission:

7. Still on the Tableau App, go to Authentication menu on the left and confirm you have a web platform with the same Redirect URI you’ve configured in step 2 above (leave everything else as is):

Next we’ll be following this guide to create a Custom B2C policy that will be leveraged by Tableau during the OpenID Connect authentication flow (i.e. the Sign-in policy):

8. On the main page of your Azure AD B2C tenant, go to Indentity and Experience Framework and then go to Policy keys

9. Create a signing key with the following settings: Options=Generate , Name=TokenSigningKeyContainer, Key type=RSA, Key usage=Signature.

10. Create the encryption key: Options=Generate, Name=TokenEncryptionKeyContainer, Key type=RSA, Key usage=Encryption

You’ll end up with something like this:

11. Follow this guide to register the two applications that it uses to sign up and sign in users with local accounts: IdentityExperienceFramework, a web API, and ProxyIdentityExperienceFramework, a native app with delegated permission to the IdentityExperienceFramework app. You will end up with something like this (take note of the two new application ids):

12. Download the Custom policy starter pack from Github (zip file)

13. Extract it and locate the policy pack that suit you better. I’ll be using the LocalAccounts one, as I’m happy to create the test users in Azure AD B2C directly (i.e. Azure AD B2C is acting as the “complete” IAM solution here). From a Tableau perspective, the instructions are the same for any of them. These are the xml files we need:

14. Using your favourite text editor, search and replace the string yourtenant with the name of your Azure AD B2C tenant. Important. make sure you replace this on ALL files in this folder!!!

15. In LocalAccounts/TrustFrameworkExtensions.xml replace the two places you find IdentityExperienceFrameworkAppId with the corresponding ones you got on step 11.

16. Very important: Since we will be authenticating in Tableau based on the email of the B2C user, inLocalAccounts/SignUpOrSignIn.xmlwe need to add the following output claim:

<OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email" />

Note: by default Tableau uses email as the claim to match any new user signing in via OIDC. You can check it by running the command: tsm configuration get -k vizportal.openid.username_claim

and you may change it to anything needed (see my troubleshooting tips below, before you decide on venturing to change this!), e.g: tsm configuration set -k vizportal.openid.username_claim -v <new-claim>

Also Very important: to enable iframe authentication (as opposed to popup auth), we need to instruct Azure that we are allow-listing our domains as trusted, in the eyes of their Content Security Policies. To do so, inLocalAccounts/SignUpOrSignIn.xmladd the following under the RelayingParty element:

<UserJourneyBehaviors><JourneyFraming Enabled="true" Sources="https://<your-tenant-name> https://<your-tableau-server-hostname>" /></UserJourneyBehaviors>

The SignUpOrSignIn.xmlfile will look like this with these two critical modifications:

17. Back in Azure portal, upload these modified custom policies in this exact order:

a. TrustFrameworkBase.xmlb. TrustFrameworkLocalization.xmlc. TrustFrameworkExtensions.xmld. SignUpOrSignin.xmle. ProfileEdit.xmlf. PasswordReset.xml

You’ll end up with something like this:

We’re done with Azure AD B2C config. Take a deep breath :D

Tableau Server OpenID config:

18. If you haven’t yet done so, create the same test user as in Azure B2C (i.e. in our case, the Tableau username must be the B2C user’s email, as this is our claim):

19. Run this command to configure OIDC with the B2C parameters:

tsm authentication openid configure --client-id <B2c-Tableau-App-ClientID> --client-secret <B2c-Tableau-App-Secret> --config-url <B2c-OpenID-UrL> --return-url <Tableau-Return-UrL>


<B2c-Tableau-App-ClientID> = see step 2<B2c-Tableau-App-Secret> = see step 3<B2c-OpenID-UrL> =  https://<tenant-name><tenant-name><b2c-signin-policyname>/v2.0/.well-known/openid-configuration<b2c-signin-policyname> = B2C_1A_SIGNUP_SIGNIN<Tableau-Return-UrL> = TableauServerHostName, e.g.

20. Enable iFrame Authentication (so that users do not need to interact with the embedded frame and click to iniciate a popup sign in):

tsm configuration set –k wgserver.openid.iframed_idp.enabled -v true

21. Enable OpenId:

tsm authentication openid enable

22. Apply pending changes and restart the server

tsm pending-changes apply

That’s it!

SPA app and Tableau Embedded with iframe SSO auth. Both leveraging the same OpenID IdP (Azure AD B2c)


23. If you need to do some troubleshooting, enable enhanced logging with these two commands (the latter of these flags were not documented, at the time of writing this blog):

tsm configuration set -k vizportal.log.level -v debugtsm configuration set -k vizportal.openid.full_server_request_logging_enabled -v true

The toubleshooting tools you need:

24. TLV — Tableau Log Viewer: to see the full message exchange between Tableau And B2C.

  • Open the following file: C:\ProgramData\Tableau\Tableau Server\data\tabsvc\logs\vizportal\vizportal_node1–0.log
  • Set to Live
  • Set Highligh Only Mode, on string: openid

25. Look for a message containing the “Full Response Data” and copy the id_token

26. Navigate to to decode this token and see the claims sent to Tableau Server:

Demo Troubleshooting:

Data Geek