JWT embedding with .Net

I've just lost a morning persuading JWT to work in .Net, so hopefully this will save someone else a load of bother! Maybe somebody has a simpler approach. If so, please let me know. The code below could very easily be abbreviated. I've kept it long-winded to make it easier to follow.

When you select the option to embed a dashboard in an application, you see some nice simple Node.js (or other) code. We can assume there's an awful lot going on behind the scenes, because the C# code is much more work.
First of all, I'm old fashioned, so like to strongly type everything. For some reason, that wouldn't work, so we're back to using var to declare stuff. I know it's not the same as Variant in VB, but looks too similar for me to want to use it!

Here goes:
First add JWT to Visual Studio. Right click your project and select 'Manage Nuget Packages'
Search for System.IdentityModel.Tokens.JWT and install. You'll need to be running .Net 4.0 for this to install.
Add to your projects using:
using System.IdentityModel.Tokens.Jwt;
using System.IdentityModel.Tokens;
All you really need is the security token's string. This contains a reference to the dashboard's ID (not the public GUID). This starts at one and goes up from there.

Here's my method:

private string getToken(Int16 dashboardId)
{
//key is the METABASE_SECRET_KEY shown in the sample. It's the same for all dashboards on the server. Should really be in web.config. Put your value here.
string key = "9de2cc5c218e96c5450fb20c469309092cdad8ad9976ffec4aa83e56ed9d6542";
//some gubbins to setup the credential generation
var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
var credentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
var header = new JwtHeader(credentials);
//the awkward bit. Looks simpler in the sample code, but .Net JWT needs dictionaries to pass the values as it doesn't handle any complexity very well..
//dash contains the information about the resource. It could be 'question' if that's all you're embedding.
var dash = new Dictionary<string, Int16>();
dash.Add("dashboard", dashboardId);

//Empty dictionary for the params. Anything else gives odd results
var pars = new Dictionary<string, string>();

//create the payload
JwtPayload payload = new JwtPayload
{
{"resource",dash } ,
{"params" ,pars}
};
//Finally some more gubbins before the token string is passed back
var secToken = new JwtSecurityToken(header, payload);
var handler = new JwtSecurityTokenHandler();
var tokenString = handler.WriteToken(secToken);
return tokenString;
}

Then it's just a case of creating the url for the IFRAME:

METABASE_SITE_URL + "/embed/dashboard/" + tokenString + "#bordered=true&titled=true";

Personally, I prefer titled=false, but that's mostly because I use separate lists to specify the filter values in the dashboard.

If you're having any problems with odd errors, http://jwt.io has a really good debugger. You just paste your token in and it shows the payload.
It should look something like this:

{
"resource": {
"dashboard": 1
},
"params": {}
}

Note the emply braces after params (no nulls or emply strings) and the braces around the dashboard bit - square brackets are bad as are comma separated values. I'm sure there are other errors I've not seen though.

Good luck.

3 Likes

Thanks @AndrewMBaines, this information was very helpful. I want to add that I also had to change the Metabase default port of 3000 to 443 to avoid security blocking from my app. My token worked but the debugger that you referenced always said it was invalid, still, the site was informative.

Hi all, did you guys get this to work successfully with .net c#?

Yes. I had to make a minor change recently to how I specify I want the dark theme, but that's not in the code above.