JWT token - how to read?

Posted by goo on 04-Jul-2018 05:49

11.6

I am receiving an JWT token and wonder if there is a simple way of reading the info? I have checked it with jwt.io and can see the data I would like to read. Is there a way of read header and payload with progress? I am TOTALLY new to this security consept, and reading to understand. 

Posted by SJProgress on 04-Jul-2018 07:22

I once came across that there are different implementations of b64-encode, with different numbers of "=" at the and.

So if you add one or two "=" to your string it will work.

Furthermore this seems to be B64URL encoded and not B64. So you will have to replace "-" with "+" and "_" with "/" before Decoding with B64-DECODE.

All Replies

Posted by Dileep Dasa on 04-Jul-2018 05:53

No, Progress doesn't provide any such tool to extract header and payload information from a JWT token.

Posted by jmls on 04-Jul-2018 05:56

Actually, it's easy to extract the data using progress. **

Basically a JWT is just a string with the following format:

header.payload.signature

where header, payload and signature are base64 encoded strings

when decoded, header and payload are stringified json objects

you must remember that a JWT  is only encoded and signed - the contents are *not* encrypted

** never having done this, take my comment with a pinch of salt ;)

Posted by goo on 04-Jul-2018 06:02

I have tried to use base64-encode on both header and payload, without luck :-/ so I believe it is because token has been webified, so how to unwebify it and read it is my question. Is there other tools I can use? What about Auth0 ?

Posted by Mike Fechner on 04-Jul-2018 06:04

Wouldn’t you have to use base64-decode ? The data is already encoded.

Posted by jmls on 04-Jul-2018 06:06

do you mean base64-decode ?

base64 is a standard for transmitting the data across - if you've got a valid jwt then it should be .. valid .. ;) No such thing as a "webified" base64 string.

could you post the jwt that you have received in openedge ?

Posted by goo on 04-Jul-2018 06:11

I ment base64-decode :-) sorry

Posted by goo on 04-Jul-2018 06:16

This is the result from jwt.io, so the token seems valid.

Posted by jmls on 04-Jul-2018 06:19

I'm sure the token is valid. The jwt string you get in openedge is header.payload.signature so did you base64-decode(entry(2,jwt,".") ?

Posted by goo on 04-Jul-2018 06:28

Correct,

This is the header....

eyJraWQiOiJtcVQ1QTNMT1NJSGJwS3JzY2IzRUhHcnItV0lGUmZMZGFxWl81SjlHUjlzIiwiYWxnIjoiUlMyNTYifQ

Posted by jmls on 04-Jul-2018 06:43

an online base64 decode gives 

{"kid":"mqT5A3LOSIHbpKrscb3EHGrr-WIFRfLdaqZ_5J9GR9s","alg":"RS256"}

so not sure why the OE version would not work. Is your longchar coded to UTF-8 ?

Posted by goo on 04-Jul-2018 06:57

def var mPnt as Memptr no-undo.

def var lcTest as longchar no-undo.

fix-codepage(lcTest) = 'utf-8'.

lcTest = "eyJraWQiOiJtcVQ1QTNMT1NJSGJwS3JzY2IzRUhHcnItV0lGUmZMZGFxWl81SjlHUjlzIiwiYWxnIjoiUlMyNTYifQ".

mPnt = base64-decode(lcTest).

CATCH eAny AS Progress.Lang.Error :

 MESSAGE eAny:GetMessage(1)

 VIEW-AS ALERT-BOX.  

END CATCH.

Gives me an error....:

Error converting Base64 to RAW (12119)

Posted by Brian Laferte on 04-Jul-2018 07:14

Even if you get the ABL to decode this, you won’t have verified it so how can you trust the payload isn’t forged?


If you are using .Net there is a dead simple control by Chilkat (https://www.chilkatsoft.com/refdoc/csJwtRef.html) that you can use to decode, validate, and create JWT tokens.   

If .Net isn’t your thing, there is a simple node.js package to do the same (https://www.npmjs.com/package/jwt). 

If neither of those work for you and you are using PAS, Spring security can do all the heavy lifting and return a client principal to the ABL for easy handling, though the setup can be confusing the first time you do it.  


Brian Laferte
401-499-6666

'Ambition leads me not only farther than any man has been before me, but as far as I think it possible for man to go.' -- James Cooke

Posted by SJProgress on 04-Jul-2018 07:22

I once came across that there are different implementations of b64-encode, with different numbers of "=" at the and.

So if you add one or two "=" to your string it will work.

Furthermore this seems to be B64URL encoded and not B64. So you will have to replace "-" with "+" and "_" with "/" before Decoding with B64-DECODE.

Posted by goo on 04-Jul-2018 07:22

I just want to read it, but .Net should be ok, I hope 😊. Have you done coding using Chilkat’s control?
 
//Geir Otto
 

Posted by goo on 04-Jul-2018 07:34

You are so correct :-) that did it. It was lack of == at the end. I will also check regarding URL encoding.

Posted by brianlafertewk on 04-Jul-2018 13:30

Here is some sample code that will read a token using the Chilkat .NET control and return a JSONObject with the payload and header.  Stuff it inside a class method or a called procedure.

DEFINE INPUT PARAMETER ipToken       AS CHARACTER         NO-UNDO.

DEFINE VARIABLE ckGlobal      AS Chilkat.Global    NO-UNDO.
DEFINE VARIABLE publicKey     AS Chilkat.PublicKey NO-UNDO.
DEFINE VARIABLE jwt           AS Chilkat.Jwt       NO-UNDO.
       
DEFINE VARIABLE cTokenPayload AS CHARACTER         NO-UNDO.       
DEFINE VARIABLE cTokenHeader  AS CHARACTER         NO-UNDO.       
DEFINE VARIABLE oJSONParser   AS ObjectModelParser NO-UNDO.
DEFINE VARIABLE tokenPayload  AS JsonObject        NO-UNDO.
DEFINE VARIABLE tokenHeader   AS JsonObject        NO-UNDO.
DEFINE VARIABLE tokenObject   AS JsonObject        NO-UNDO.
 
      // Authorize Chilkat Bundle       
ckGlobal = NEW Chilkat.Global().
ckGlobal:UnlockBundle('MyChilkatAuthCode').
   
IF NOT ckGlobal:LastMethodSuccess THEN
  UNDO, THROW NEW PROGRESS.Lang.AppError(ckGlobal:LastErrorText).
 
// Load the Public Key to verify the token
publicKey = NEW Chilkat.PublicKey().         
publicKey:LoadFromFile("PublicKey.pem").
IF NOT publicKey:LastMethodSuccess THEN
  UNDO, THROW NEW PROGRESS.Lang.AppError("Invalid Public Key: " + publicKey:LastErrorText,500).
 
      // Get a JWT instance
jwt = NEW Chilkat.Jwt().
 
IF NOT jwt:LastMethodSuccess THEN
  UNDO, THROW NEW PROGRESS.Lang.AppError("Invalid Token: " + jwt:LastErrorText,500).
 
ASSIGN
  cTokenPayload = jwt:GetPayload(ipToken)
  cTokenHeader  = jwt:GetHeader(ipToken).
   
oJSONParser = NEW ObjectModelParser().
tokenPayload = CAST(oJSONParser:Parse(cTokenPayload),JsonObject).
tokenHeader = CAST(oJSONParser:Parse(cTokenHeader),JsonObject).

tokenObject = NEW JsonObject().
tokenObject:Add("header",tokenHeader).
tokenObject:Add("payload",tokenPayload).
 
RETURN tokenObject.
 
CATCH e AS Progress.Lang.Error :
  UNDO, THROW e.       
END CATCH. 
 

 

Posted by goo on 04-Jul-2018 14:46

Thanks Brian !
 

Posted by slegian-bva on 04-Jul-2018 18:06

We tried the same, with plain progress first and hit that Base64 issue, then had to deal with certificates so settled on the System.IdentityModel.Tokens.Jwt package from Microsoft, though it seems to be in a state of flux and changes from one version to the next. Got the 5.2.2 version working and can now validate an auth0 issued, RS256 signed jwt...

Posted by goo on 05-Jul-2018 00:22

Nice to know :-) was it straight forward using it? 

Sendt fra min iPad

5. jul. 2018 kl. 01:07 skrev slegian-bva <bounce-slegian-bva@community.progress.com>:

Update from Progress Community
slegian-bva

We tried the same, with plain progress first and hit that Base64 issue, then had to deal with certificates so settled on the System.IdentityModel.Tokens.Jwt package from Microsoft, though it seems to be in a state of flux and changes from one version to the next. Got the 5.2.2 version working and can now validate an auth0 issued, RS256 signed jwt...

View online

 

You received this notification because you subscribed to the forum.  To unsubscribe from only this thread, go here.

Flag this post as spam/abuse.

Posted by slegian-bva on 05-Jul-2018 00:39

Sort of, once we sorted out the working version and the mechanics. The certificate business made things a bit more complicated.

MS seem to be still working on this, the API changed from 4.xx to 5.xx, the doco was not in sync, the samples were around 4.xx and the certificate business only worked in 5.xx

Free code so can't complain...

It turned out we need 2 assemblies - Microsoft.IdentityModel.Tokens, Version=5.2.2.0 and System.IdentityModel.Tokens.Jwt, Version=5.2.2.0

You then use the System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler:ValidateToken to get a yay/nay and a "Microsoft.IdentityModel.Tokens.SecurityToken" object which you can then cast to System.IdentityModel.Tokens.Jwt.JwtSecurityToken which is a nice JWT representation.

I'll see if I can put up some sample code...

Posted by goo on 05-Jul-2018 00:58

Your the man :-) thanx

Sendt fra min iPad

5. jul. 2018 kl. 07:41 skrev slegian-bva <bounce-slegian-bva@community.progress.com>:

 Update from Progress Community
slegian-bva

Sort of, once we sorted out the working version and the mechanics. The certificate business made things a bit more complicated.

MS seem to be still working on this, the API changed from 4.xx to 5.xx, the doco was not in sync, the samples were around 4.xx and the certificate business only worked in 5.xx

Free code so can't complain...

It turned out we need 2 assemblies - Microsoft.IdentityModel.Tokens, Version=5.2.2.0 and System.IdentityModel.Tokens.Jwt, Version=5.2.2.0

You then use the System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler:ValidateToken to get a yay/nay and a "Microsoft.IdentityModel.Tokens.SecurityToken" object which you can then cast to System.IdentityModel.Tokens.Jwt.JwtSecurityToken which is a nice JWT representation.

I'll see if I can put up some sample code...

View online

 

You received this notification because you subscribed to the forum.  To unsubscribe from only this thread, go here.

Flag this post as spam/abuse.

Posted by Peter Judge on 06-Jul-2018 15:22

I think I would log this as a bug  - it’s at least worth a conversation with Tech Support, since  the = or == are meaningful (https://en.wikipedia.org/wiki/Base64 ).
 
You (as an ABL programmer) shouldn’t have to deal with figuring out whether to add zero, 1 or 2 = to decode the string.

This thread is closed