Tableau Server OpenID SSO integration with Azure AD B2C for seamless iframe authentication
Contrary to popular belief, stating from Oct 2020 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: Azure has been known to block any sort of in-frame authentication flows, but now with just a couple of lines of code you can define a custom CSP policy in B2C that allows for such for your trusted domains. This new feature was still in public preview at the time of this writing).
- 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.
- 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. https://tableau.mycompany.com)
- Admin access to both Tableau Server GUI and its VM/container
- Tableau Log Viewer installed (for troubleshooting config issues)
- 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 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!!!
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, in
LocalAccounts/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, in
LocalAccounts/SignUpOrSignIn.xmladd the following under the RelayingParty element:
<UserJourneyBehaviors><JourneyFraming Enabled="true" Sources="https://<your-tenant-name>.b2clogin.com https://<your-tableau-server-hostname>" /></UserJourneyBehaviors>
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>.b2clogin.com/<tenant-name>.onmicrosoft.com/<b2c-signin-policyname>/v2.0/.well-known/openid-configuration<b2c-signin-policyname> = B2C_1A_SIGNUP_SIGNIN<Tableau-Return-UrL> = TableauServerHostName, e.g. https://tableau-example.com)
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. (optional) Set Tableau to use client_secret_post instead of client_secret_basic (default), but only try this step if you are getting Error 69: “Unable to Sign In” errors:
tsm configuration set -k vizportal.openid.client_authentication -v client_secret_post
22. (optional) Try this one only if you are getting this error: OpenID Connect Authentication Flow- Error 10060. I’ve managed to get away many times without this, but for one specific client, so there’s some B2C config that may require this. Perhaps it’s needed when you implemented client_secret_post (step 21 above):
tsm authentication openid configure --custom-scope-name “openid <B2c-Tableau-App-ClientID>”
where <B2c-Tableau-App-ClientID> is the Tableau client app ID you got in step 2 above.
23. Enable OpenId:
tsm authentication openid enable
24. Apply pending changes and restart the server
tsm pending-changes apply
25. 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:
26. 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
27. Look for a message containing the “Full Response Data” and copy the id_token
28. Navigate to www.jstoolset.com/jwt to decode this token and see the claims sent to Tableau Server: