JWT token - how to read? - Forum - OpenEdge Development - Progress Community
 Forum

JWT token - how to read?

This question is answered

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. 

Verified Answer
  • 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
  • No, Progress doesn't provide any such tool to extract header and payload information from a JWT token.

  • 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 ;)

  • 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 ?

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

    Architect of the SmartComponent Library and WinKit

    Consultingwerk Ltd.

  • I ment base64-decode :-) sorry

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

  • 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,".") ?

  • Correct,

    This is the header....

    eyJraWQiOiJtcVQ1QTNMT1NJSGJwS3JzY2IzRUhHcnItV0lGUmZMZGFxWl81SjlHUjlzIiwiYWxnIjoiUlMyNTYifQ

  • 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 ?

  • 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)

  • 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
  • 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.

  • I just want to read it, but .Net should be ok, I hope 😊. Have you done coding using Chilkat’s control?
     
    //Geir Otto
     
  • You are so correct :-) that did it. It was lack of == at the end. I will also check regarding URL encoding.

  • 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.