Per User API Keys Not Working

I’m following the guidance for getting per user api keys: User API keys specification.

I’ve gone through the steps: client generates a public/private key pair and return url, goes to a discourse route, user gives approval to discourse to use the app, and discourse generates an api key.

But when discourse sends back the API key as a “payload” in the return url, that key doesn’t work. I try to decrypt it, but I can’t.

I plug that key into some standard javascript decryption (like in the answer here), and I get a “length is invalid” error. (or DATA_LEN_NOT_EQUAL_TO_MOD_LEN , depending on decrypt javascript method I am using)

Any ideas for how to address?

This is a crucial piece of functionality, so any help is really appreciated.

Do I need to change the key provided in the payload in some way? Is it possible that the payload provided key doesn’t work?

A little more detail:

I think my overall method is right, because discourse provides another method of getting a per user key, and I’m able to decrypt that key:

If I leave out the redirect url in the request to discourse, discourse doesn’t do a redirect. Instead, it prints a key on the screen for the user to copy.

That key is shorter than the key provided in a “payload” (it’s about 684 characters, and the payload key is about 762). And that key works–I am able to decrypt it fine using javascript.

But asking the user to copy and paste an API key is confusing to users–the proper flow is getting the key from the payload. How do I get that payload key to work?

Any ideas for this one? How can I get the payload-provided api key to work?

I’ve gotten it to work. @RGJ helpfully pointed the following out:

When discourse does the redirect and sends the API key to be decoded as a payload in the redirect url, that key goes through url encoding. So to get the actual API key, you need to do URL decoding on the payload. The result is the properly working API key (which matches the length of the key that discourse prints on the screen).

I have provided the steps that I follow to get this to work here: