Ask

How do I get a dropdown into a form whose options depend on the current user or another field?

If the same constraint applies across many forms — everything scoped to the user's organisation — it is worth pushing it down to the query layer rather than repeating the initialiser pattern in twenty forms.

A manager or a scoped query that is always organisation-filtered means the form's option source is correct by construction, and a developer who forgets the pattern gets a safe default instead of a leak.

More work up front. Much better than relying on everyone remembering.

1 · in/fullstack ·

Verification fails with "jwt malformed" — the token looks fine when I print it

"Malformed" is a very specific complaint and it happens before any signature checking: the library could not split the string into the three dot-separated parts a token is made of. So the secret is irrelevant — it never got that far — which is why signing working tells you nothing.

A token is header.payload.signature, three base64url segments separated by two dots. Count the dots in what you are passing. If it is not exactly two, that is your answer, and the cause is nearly always one of these:

1. You are passing the whole authorization header. The header value is Bearer <token>. Passing that string wholesale gives the library Bearer eyJ... which has a space and a word in front of the header segment. This is the most common cause by a wide margin, and the fix is to strip the scheme — split on whitespace and take the second part, and handle the case where the header is missing rather than indexing into nothing.

2. The value is undefined, null or an empty string. A missing header, a cookie that was never set, a typo in the property name. Stringified, these become "undefined" or "", which is a string, so your log looks like it printed something. Log the type and the length alongside the value — undefined and a real token look far more different in that form.

3. It is an object, not a string. If something already parsed or wrapped the token, you are handing the library the wrong type.

4. It was truncated or mangled in transit. Cookies have size limits, and a token with a large payload can be silently cut off. Proxies occasionally mangle long headers. Compare the length at the point of issue with the length at the point of verification — if they differ, that is the whole problem and no amount of looking at the code will show it.

5. It was double-encoded. Stored as JSON inside a cookie, or URL-encoded somewhere in the chain, so what arrives has quotes around it or percent-escapes in it. Quotes are the giveaway: a token with a leading " is a token that was JSON-stringified.

How to find it in one minute. At the verification site, log three things: the length, the number of dots, and the first and last ten characters. That distinguishes every case above immediately, and it is much more informative than logging the token itself — which you should not be doing in anything but local debugging anyway, since a log with tokens in it is a log full of live credentials.

Then decode without verifying. Every library has a decode function that parses the token without checking the signature. If decode succeeds and verify fails, you have a genuine signature or expiry problem and the causes are completely different — a mismatched secret, the wrong algorithm, or clock skew. If decode also fails with malformed, it is the string, and the list above applies.

30 · in/sessions-vs-jwt ·

Single-page app cannot renew its token — the renewal call comes back saying there is no refresh token

Practical detail while you debug: check what the token actually contains after sign-in, rather than what you asked for.

Decode the access token and look at its scopes. If the offline access scope is not in there, your request for it was not granted — and the reason is usually the application registration rather than your code, so you can stop rereading the front end.

That one check distinguishes "I did not ask correctly" from "I asked and was refused", which are different fixes in different places.

21 · in/sessions-vs-jwt ·