Web Connection
How to parse a JWT Token
Gravatar is a globally recognized avatar based on your email address. How to parse a JWT Token
  Scott R
  All
  Jun 23, 2022 @ 11:15am

Hi Rick,

We are doing some oAuth stuff with gmail using webconnect as the server side and wwHTTP to make the request. We are getting back a JWT token as part of the response but we have no idea how to parse it / interpret it (i.e. it has the users email address in it). Is there a way in VFP / web connect to parse this or do you know of any built in C# stuff we could call with wwDotNetBridge without writing our own parser?

Thanks,

Scott

Gravatar is a globally recognized avatar based on your email address. re: How to parse a JWT Token
  Scott R
  Scott R
  Jun 23, 2022 @ 11:27am

Never mind. Found another web call we can make that returns it back in normal JSON format. If you know a quick way to parse the JWT token great, if not, don't worry about it.

Thanks.

Gravatar is a globally recognized avatar based on your email address. re: How to parse a JWT Token
  Rick Strahl
  Scott R
  Jun 23, 2022 @ 05:15pm

There are JWT Token classes in .NET. System.IdentityModel.JwtTokenHandler.

var token = "jwt-token-here";
var new JwtSecurityTokenHandler().ReadToken(token);

Note this will unpack the public data, but won't validate the token - there's a separate method for that to which you have to provide the keys to decrypt the token.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: How to parse a JWT Token
  Scott R
  Rick Strahl
  Jun 27, 2022 @ 10:18am

Hey Rick,

Thanks! Is there a way to call this directly from wwDotNetBridge or do I need to write a c# dll and load it in to the dotNetBridge?

Thanks,

Scott

Gravatar is a globally recognized avatar based on your email address. re: How to parse a JWT Token
  Rick Strahl
  Scott R
  Jun 27, 2022 @ 11:42am

You should be able to call directly into this from FoxPro. Looks like it's a simple method call, but I'm not sure of the details required to parse the token. If I remember right this will decode the token but won't validate.

Token data is never secure - the secure part of the token is the signature that's used to verify that the data hasn't been tempered with.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: How to parse a JWT Token
  Scott R
  Rick Strahl
  Jun 27, 2022 @ 01:00pm

Hey Rick,

So I was able to load the assembly but I can't get method to work / can't create an instance to call the methods I need.

This is working to load the assembly

oBridge.loadAssembly('System.IdentityModel.Tokens.Jwt, Version=5.2.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35')
IF !EMPTY(oBridge.cErrorMsg)
	SET PATH TO (m.oldPath)
	SELECT (m.oldArea)
	RETURN 'Failed to Load JWT Assembly: ' + oBridge.cErrorMsg
ENDIF

However, I can't get an instance of the JwtSecurityTokenHandler or the JwtSecurityToken.

I've tried:

oBridge.CreateInstance('System.IdentityModel.Tokens.Jwt.JwtSecurityToken')
****
oBridge.CreateInstance('System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler')
****
oBridge.InvokeStaticMethod('Microsoft.IdentityModel.Tokens.SecurityTokenHandler', 'Create')

It always errors out the same with: Type is not loaded. Please make sure you call LoadAssembly first.

But the load assembly IS working (at least no error messages in oBridge.cErrorMsg). Any thoughts?

Thanks,

Scott

Gravatar is a globally recognized avatar based on your email address. re: How to parse a JWT Token
  Rick Strahl
  Scott R
  Jun 27, 2022 @ 10:51pm

From what I see that library comes from a NuGet package so you have to get a hold of the package and the files in it.

Easiest way to do this I think:

Create a .NET Project file as a text file

// JwtTest.csproj
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net472</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.20.0" />
  </ItemGroup>

</Project>

Open a command window at the location of the file. Make sure you have the .NET 6.0 SDK installed. Then build:

dotnet build

This creates a bin folder and the package content will be dumped in it. you probably should move the files from there into your project folder (don't copy the output assembly just the System. ones).

I spent way too much time on this, and this is probably one instance where I would have chosen to create a .NET wrapper 😄. BUt it's possible to do this with wwDotnetBridge:

CLEAR
DO wconnect

do wwDotNetBridge
LOCAL loBridge as wwDotNetBridge

loBridge = GetwwDotnetBridge()

? loBridge.LoadAssembly("C:\temp\TestLibrary\TestLibrary\bin\Debug\net472\System.IdentityModel.Tokens.Jwt.dll")
? loBridge.cErrorMsg

TEXT TO lcToken NOSHOW FLAGS 1
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
ENDTEXT

? lcToken


loInstance = loBridge.CreateInstance("System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler")
? loBridge.ceRRORMSG
? loInstance && object

loResult = loBridge.Invokemethod(loInstance, "ReadToken",lcToken)
? loResult && object

lopayload = loBridge.GetProperty(loResult,"PayLoad")
? loPayLoad


*** Old way passing by reference with ComValue
loResult = loBridge.CreateComValue()
loResult.Value = ""

? loBridge.InvokeMethod(loPayLoad,"TryGetValue","name",@loResult)
? loResult.Value

? loBridge.InvokeMethod(loPayLoad,"TryGetValue","sub",@loResult)
? loResult.Value

*** Simpler with updated version
? loBridge.odotnetBridge.GetDictionaryItem(loPayLoad, "name")
? loBridge.odotnetBridge.GetDictionaryItem(loPayLoad, "sub")

As I was working through this I realized that it's crazy difficult to get a result for a dictionary value so I added a new method to wwDotnetBridge to make this easier with GetDictionaryItem().

You can grab this updated version from:

https://west-wind.com/files/WebConnectionExpermental.zip

Easier with .NET

Looking at this I still think this is one of those cases where it makes sense to create a wrapper and just do it in .NET. You can play around with this in LinqPad to get it to work.

Here's the same code in .NET and it's a heck of a lot easier to understand what's going on:

void Main()
{
	var token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
	
	var handler = new JwtSecurityTokenHandler();
	var parsed = handler.ReadJwtToken(token);
	
	var sub = parsed.Payload["sub"];
	sub.Dump();
	var name = parsed.Payload["name"];
	name.Dump();

	parsed.Dump();
}

Especially since you kind of need to set up a .NET project anyway to get the NuGet package...

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: How to parse a JWT Token
  Scott R
  Rick Strahl
  Jun 28, 2022 @ 09:45am

Thanks Rick! We'll take a look into it and see what we can figure out. Definitely looks like the wrapper might be a good way to go in this case..

© 1996-2024