Troubleshooting Looker SSO Embed URL Generation

Powered by Looker is a neat way to share data with the world. If you’re interested in creating a proof of concept, I highly recommend checking out this post.

If you’re having issues with your embedded Looks and/or dashboards, making sure the embed URL is properly constructed is a good place to start. Creating an application to write a URL is not something we currently do, but there is some example code here.

The Steps You’ll Take

To check URL construction, I always run through these steps (more on each to later):

  1. Make sure the Look or dashboard exists on the “production” version of your instance
  2. Make sure users are authenticated with the correct permission set
  3. Make sure URL parameters are correctly formed
  4. Confirm that everything is spelled correctly
Handy Tools

To run through these checks, I find it helpful to have a couple of tools easily available:

  • A URL decoder (I use this one, for no particular reason)
  • A URL encoding reference (I use W3Schools, say what you will)
  • Looker logs (if you have access to your instance’s logs, they can provide some helpful error messages)

Check production

If a dashboard or Look does not live on the production version of your instance (outside of developer mode), then you will not be able to get this to work. If you can’t find it, on production, make sure it’s created, saved, committed, and pushed.

Check permissions

A complete walk through of Looker’s permissioning system is outside of the scope of this post, but I highly recommend this document. It’s great. If you’re looking to limit data access, this is a great resource.

Simply put, if a user doesn’t have access and permissions to see the Look, they’ll get a 404. For example, if the embedded user doesn’t have see_lookml_dashboards and the embeded dashboard is a LookML dashboard, we got problems.

Check URL parameters

The API call should produce an encoded URL that takes the form:

https://do.main.com/login/embed/%2Fembed%2Fitem_name_here?nonce=%22something%22&time=some_time_value&session_length=some_other_time_value&external_user_id=%22an_id%22&permissions=%5B%22permission_one%22%2C%22permission_two%22%2C%22permission_three%22...%22%2C%22permission_n-1%22%2C%22permission_n%22%5D&models=%5B%22model_one%22%2C%22model_two%22%2C%22model_three%22...%22%2C%22model_n-1%22%2C%22model_n%22%5D&access_filters=%7B%22model_one%22%3A%7B%22view_name.field_name%22%3A%22value%22%7D%2C%22model_two%22%3A%7B%22other_view_name.other_field_name%22%3A%22other_value%22%7D%7D&first_name=%22a_first_name%22&last_name=%22a_last_name%22&force_logout_login=true_or_false&signature=some_signature

We’ll go over each parameter, but the basic form is an address plus key-value pairs containing some information. Decoded, an embed URL should to look like this:

https://do.main.com/login/embed//embed/item_name_here?nonce="something"&time=some_time_value&session_length=some_other_time_value&external_user_id="an_id"&permissions=["permission_one","permission_two","permission_three"...","permission_n-1","permission_n"]&models=["model_one","model_two","model_three"...","model_n-1","model_n"]&access_filters={"model_one":{"view_name.field_name":"value"},"model_two":{"other_view_name.other_field_name":"other_value"}}&first_name="a_first_name"&last_name="a_last_name"&force_logout_login=true_or_false&signature=some_signature

The address

This should look something like https://do.main.com/login/embed/%2Fembed%2Fitem_name_here? (not decoded)

  • do.main is your Looker instance’s domain
  • item_name_here is the name of your dashboard or Look. A LookML dashboard will be something like dashboards%2Fmodel_name_here%2Fdashboard_name_here and a user-defined dashboard will be something like dashboards%2Fdashboard_number_here%20F

The parameters

  • nonce is a value that identifies this request (16 character hexadecimal string). It shouldn’t be re-used (it’s a single sign-on) and should come from by a secure random number generator.
  • time is a timestamp to identify when the session begins. I don’t believe it allows for decimal values, but I could be mistaken
  • session_length is how long a user should be authenticated (in seconds). Pick something reasonable (no more than 30 days)
  • external_user_id is Looker instance user ID of the user being authenticated
  • permissionsshould be a grouping of Looker permissions. Something like this might work permissions=%5b%22see_user_dashboards%22%2c%22see_lookml_dashboards%22%2c%22access_data%22%2c%22see_looks
  • models is a group of models your user will have access to. Make sure they’re spelled correctly and in quotes. Something like this might work models=%5B%22faa%22%2C%22thelook%22%5D
  • access_filters should be the group of access_filter_fields that are applied to your instance. If you don’t use them, something like this should work access_filters%3D%7B%22faa%22%3A%7B%7D%2C%22thelook%22%3A%7B%7D%7D. If you use them, try this access_filters={"faa":{"aircraft.tail_number":"1"},"thelook":{"users.user_id":"2"}}
  • a_first_name will be the first name of your authenticated Looker user, as displayed in Looker
  • a_last_name will be the last name of your authenticated Looker user, as displayed in Looker
  • force_logout_login determines whether currently logged-in users will be logged out before authentication. I recommend setting this to true, at least for testing purposes
  • some_signature will be generated by your code. It is used by Looker to verify that the secret used to sign the request is valid and that the parameters that are present in the request are identical to those that were signed when the signature was generated.

Check spelling

If anything’s spelled incorrectly, we’ll run into trouble. Typos happen (I type dimesnion more often than I care to admit), so make sure all model names, files, etc. are spelled properly.

Other things to note

  • I’ve seen certain browsers not like %20f and only take %20F as an encoded /
  • You may want to use an encoder reference to make sure you’ve got your /s, {s, and company straight
  • Note a lack of spaces between decoded parameters
  • I don’t believe that the string to sign should have a https://

Version note

This was written and tested on Looker release 3.20.

4 39 5,288
39 REPLIES 39

If you are receiving authentication errors (i.e. the signature is not correct), make sure your host is stored without https://. For example, it should just be company.looker.com or localhost:9999.

Hi Cutler,
It’s a really help full post while troubleshoot a related issue for me.

Can you please add a sso_embed.cs (C# example code file) into GitHub under looker/looker_embed_sso_examples.

Thanks!

brad1
Participant II

@Mahtab_Hussain I just went through this process of creating the embed code and troubleshooting it. I recommend you use one of the examples, I used the python example. Use a static time, and a static nonce value and run your code against their examples. If your code outputs the same url, you know its working. I know its a bit of a hassle but it was super useful in my troubleshooting. Once I complete my implementation I’m going to pull request it into that repo, but my implementation is in APEX.

Thanks Brad,

I am sending unique nonce value every time but still getting “Single sign on failure. Please contact an administrator.” error message on Login page.

brad1
Participant II

@Mahtab_Hussain You can’t use a static value. This is just to test your implementation. So create the code in c#, then use static values in a python implementation and test your code to see if it outputs the same url. If it does, you know your code works and you can remove the static values.

Hey @Mahtab_Hussain, glad you liked the post!

A C# pseudocode example is not on our near-term product roadmap, but we’re happy to review pull requests to the examples repo.

I also find it super helpful to check errors in your Looker instance’s logs. If you’re an administrator on a Looker-hosted instance, you should be able to view recent log entries at something like https://your_domain.looker.com/admin/log. If you host your own instance, you can grab the full logs off of the machine running it.

Hope that helps!

Hello @brad1 and @cutler,

Thanks for assistance. 😄

I have successfully create C# implementation of embed code, your reply help me a lot.

Excellent!
A+ 🍎📚

Hi @brad1 and @cutler,

How or from where can we get the model name (in my code
for ex.- models ="[“race_results”]"😉 and accessFilters (For ex.- accessFilters =
("{“race_results”:{“races.id”:1}}")😉

To pass these parameter from my code for other newly created

dashboards in SSO embed code.

Please assist.

Is it the case that you’re using the SSO embed code to create a new dashboard (a fresh one that doesn’t exist in Looker)?

No, for existing one

@Mahtab_Hussain It sounds like this might be getting specific to your implementation. Happy to help you troubleshoot any errors you’re getting, but it might be more efficient if you visit help.looker.com with the problem your facing, any associated error messages and relevant log snippets. From there, we can help narrow down where things might be breaking down.

Hi @cutler and @brad1
I found that i can use SDK all_dashboards() looker API to get all dashboard and their associated metadata, Can you please share any code example, to show how can i use these all_dashboards() API method in my code, to get the list of all dashboards and metadata.

Thanks!

@Mahtab_Hussain I don’t believe that we have any examples of an embed app that makes use of all_dashboards() handy. If you’re running into trouble, I’d be happy to point you in the right direction. Please visit us at help.looker.com with information related to the specific issue you’re facing, any error messages you’re getting, and the logs associated with the SSO embed calls.

brad1
Participant II

Oh wow @Mahtab_Hussain are you building a dynamic viewer on top of looker? So your users can browse the various dashboards but not on looker?

Yes, @brad1

srivera1
Participant III

If you still need some C# .net code please let me know. I’ll get it to you. In the mean time, I’ll work with Looker to publish it on github.

srivera1
Participant III

Looker recently added ‘hide_title’ as a query parameter but I can’t get the API to authenticate when I add this in to the url and the signature. Will ‘hide_title’ work with sso embed dashboards?

srivera1
Participant III

I’ve posted a .net example in github and posted a pull request to Looker. You can find my code below.

Randall-Reilly-EDA/looker_embed_sso_examples/blob/master/csharp-example.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Security.Cryptography;

namespace LookerEmbeddedUrl
{
    class Program
    {

        public static string _access_token = "";

        public static string _EmbedSecret = "13175ee8bf19b798911c2473565989d01234ada50fd0c591e07e13e21edf1df6"; // Hosted Looker Instance

        public static string _host = "https://company.looker.com";

        static void Main(string[] args)
This file has been truncated. show original

Hey Sonny - adding hide_title=true should work in SSO embed dashboards. Feel free to visit help.looker.com or come on chat if you are still having issues, and we can troubleshoot it with you!

Hey @srivera1

Thanks for help!

Actually we have already code in C# for sso embedding of various looker objects(looks, dashboard), and are using in our application.
But we are also looking to use all_dashboards() and other sdk API’s to get all available dashboard and their related metadata into our application programmatically from Looker.

srivera1
Participant III

I’m currently developing a .NET C# SDK for looker. I’m very interested in the API and new features coming with the API. Let’s stay connected and make sure this train keeps rolling.

Thanks

rtblair
Participant I

Can this document be updated to include documentation for the group_ids parameter introduced here:

Added the group ids to the code (#10)

* Initial pass, nothing tested or even checked for ability to compile yet 
 
* Added php group_ids code 
 
*...
changed 6 files with 45 additions and 19 deletions.

Hi all, is it possible to specify different connection models for user-defined dashboards/looks when embedding them with SSO url approach?

@Alexander_Karta As today dashboard’s are distinct per model, and models are distinct per connection. We’re building out a feature in 4.4 called user attributes which would allow you to dictate connections per user, however I may be misunderstanding your issue, and in that case user attributes would not help.

If you’re curious if you’re able to point a dashboard to a different model in the url, that is not possible. If you’re curious about pointing a model to a different connection per user, and using that model for the dashboard, that would be possible in 4.4 (see above comment).

Happy to talk use cases if you wouldn’t mind expanding on it.

@Zam thanks for the answer, I’m looking for something like described in this article for LookML dashboards but for user-defined dashboards/looks:

https://do.main.com/login/embed//embed/sso/dashboards/model_name_here/dashboard_name_here?...

where I can specify connection model and if I understood correctly from your comment it is not possible?

@Alexander_Karta It’s not possible for user-defined dashboards, as they’re are not linked to a specific model. Looks as well are objects with saved queries to them, in which they will belong to a model.

The only options you have for adjusting models via the url are with LookML dashboards and the explore page. These options due however rely on the caveat that either the LookML dashboard or the explore path do exist in the model you’re switching to. An example of what the url would look like for a model,

https://do.main.com/login/embed//embed/sso/explore/model_name_here/explore_name_here?...

Hi @All,

We are trying to generate the Embed URI for using dashboards embedding in our Salesforce. We are using Salesforce(APEX) code for generating the Encoded URI.

But, when we use the URI in the Embed URI Validator we are recieving the following errors:

  1. ‘signature’ param failed to authenticate
  2. ‘time’ param is not within 5 minutes of the server’s system time .

The latter one, we were able to resolve the error but for the prior we were not able to resolve. Even we tried to make use of online signature encoder for encoding the signature param.

Please note : we are not passing any model param for embed uri

Please help and guide us if we are missing anything.

Thanks.

Hey @vishals

Would you mind visiting help.looker.com so we can take a closer look at your code and the URI it’s generating?

Thanks!

Hi Brad, we are developing the apex code for the same but we are getting error "‘signature’ param failed to authenticate: ". Can you please help as you have already done that!! Thanks.

Hi @All!

We are trying to embed looker on our site and it seems like we reached the URL length limit.
We have a long URL to an explore page with a lot of parameters such as fields, vis, filter options and so on. The URL with embedding parameters is really long as a result.

Ability to change connection in the URL is important criteria for us. This is why we use explore screen this way.

Could you give any advice what can we do in this situation? Maybe we can decrease the length by replacing some options with shortening ones, creating some aliases for a group of parameters in Looker or something else? Or maybe we can extend the max URL length in the Looker configuration or so on?

Any idea would be great for us.

Also, could you please tell what the max length of a URL is?

Hi @sani

Could you please provide us with more details on how are you trying to change the connection using the URL?
I can see that some browsers/servers have problems with URLs over 2K characters.

Could please you tell me the length of your URL? you can email us to help.looker.com

Best,
Sara

Hello @Sara_Guzman,

We are going to change the connection this way:
https://looker.ourDomain.com:9999/login/embed//embed/explore/first_connection_model/client?fields=
https://looker.ourDomain.com:9999/login/embed//embed/explore/second_connection_model/client?fields=

Original Looker URL contains about 1990 characters. The final URL with embedding parameters contains more than 3412 characters. (I used encoded URL for calculation)

Using the url we can change the model, but we cannot change the connection. In order to dynamically change your connection, you can use the user attributes in the Additional Params field, of the Connections page in the Admin section of Looker, as shown in this Doc.

Additionally you could have multiple models that all extend a base model, but have different connections in their model file. Please let me know if this helps.

Best,
Sara

Hello @Sara_Guzman,

Thank you for the information but I still don’t understand how this can decrease the length of the Explore URL which we need to embed on our website. The “Explore” URL length is the main our problem.

Is it possible to use a short link or compress parameters in another way?

Hi @sani
It is possible to shorten the URL. Could you please visit us at help.looker.com or come to our chat support? There is more info and details we need in order to address this.

Best,
Sara

Hi,

I have been trying to implement SSO Embeding following the instructions step by step and I was getting “‘signature’ param failed to authenticate:”.

After a lot of playing around I figured out that the reason for that, was because when trying to generate the signature I was using the embed URL by its strict definition (e.g /embed/dashboards/1). However this is wrong.

What needs to be used in order to generate the signature in the above case should be the path plus the encoded embed URL (e.g /login/embed/%2Fembed%2Fdashboards%2F1)

I believe the instructions on thepage are misleading, since it’s stated that for generating the signature, the second parameter after Host should be Embed URL which is defined earlier in the page just as just the path after /login/embed/.

I hope this helpful for anyone who was confused like me.

You’re right, by George! (sorry, bad joke).

I think you’re actually right, though— This is something we should clarify.

In all of our example scripts, we specify the un-encoded URL in the url_params, so that when the actual URL is created, it can all be encoded at once. During the signature generation, we do encode just the embed url before generating the signature.

I’ll check in with the docs team about this. Thanks!

@gpaparisteidis, confirmed that we’ll want to add that in— I sent over a request to the docs team. Thanks for the eagle eyes! Glad you figured it out.