[Libwebsockets] Convenience functions for JWTs

andy at warmcat.com andy at warmcat.com
Fri Mar 12 03:26:21 CET 2021

On March 11, 2021 10:32:43 PM UTC, Andreas Weigel <andrweigel at googlemail.com> wrote:
>I'm using libwebsockets to create/sign and send JWTs to different 
>providers, which do not all expect the header fields (and are really 
>picky when they do not get one they expect "x5t" header or "typ" or 
>whatever header). There's two things I encountered and couldn't solve 

The JWT stuff is at the top of a pyramid of different layers written over the years... the motivation for the last, JWT layer was to provide login tokens for Sai (which works great).  So while it provides standardized and flexible pieces to facilitate that, it doesn't implement optional stuff not needed for that atm.

>1) x5t in JOSE header (base64url-encoded sha1sum of DER of certificate 
>used for signing); I couldn't find any way to with lws_x509_cert to 
>either get this fingerprint directly or to get at the DER
>in a buffer -- for now, I just used mbedtls directly to produce what I 
>needed, which sadly does away with the cryptolib independence.
>2) Adding header values to the JOSE header. I used lws_jwt_sign_compact
>but it does not allow for the addition of any header values besides 
>"alg". For now, I just copied the function and replaced what I needed.
>Did I miss something somewhere?

Only that I personally wrote all the layers over the years, and I'm not expecting to live forever... like the proverbial dog playing the piano the remarkable thing isn't that there are optional things unimplemented, but that this big edifice of high quality backend-independent code exists at all.

>I'm ready to provide some patches to add the functionality, but I'm not


>quite sure about the best approach.
>For 1) I would image to either add a function directly to retrieve a 
>fingerprint, or offer a function to expose the DER representation as a 
>buffer directly?.

A new tls lib agnostic fingerprint api in the lws_x509 stuff would be the way.  Because the original DER is gone after the tls library slices and dices it into its own objects.

>For 2) I thought one could add a function along the lines of
>lws_jwt_sign_with_header(struct lws_context *, struct lws_jwk *, struct
>lws_jose *, char *out, size_t out_len, char *temp, int tl, const char 
>*format, ...);

I found once functions keep evolving to acquire more args it's usually worth breaking them out into an info struct, and have earlier compatibility forms create an info struct on the stack, and call through to the new implementation under the hood.  lws_jwt_sign_compact() is already over the limit


... converting that to an info struct version will let you put whatever else you want in there cleanly, if the caller doesn't care just leave them at 0 / NULL.  This is the approach in lws_jwt_sign_token_set_cookie() already.

>and then using lws_jose_render to produce the JSON but then I noticed 
>that apart from "lws_jws_parse" there's not much to conveniently fill 
>that structure (again, am I missing something?). I thought abut passing
 >an LWS_COUNT_JOSE_HDR_ELEMENTS-long array, with values or NULL at the 
>corresponding indices. Finally, I thought it would probably be easiest 
>to just let the user pass a buffer containing the complete JSON of the 
>header he wants, parse it via lws_parse into a jose-struct to sanitize 
>the input and if ok, just copy it to the corresponding lws buffer. What
>do you think?

Is lws_jwt_sign_token_set_cookie() not already doing this, with .extra_json in the info?


>Libwebsockets mailing list
>Libwebsockets at ml.libwebsockets.org

More information about the Libwebsockets mailing list