avatarDaz

Summary

The author shares their approach to generating cryptographic random state in JavaScript for an OAuth2 implicit flow in a JavaScript SPA, using the Cryptography API for better security and performance.

Abstract

The author needed to generate a random state for an OAuth2 implicit flow in a JavaScript SPA and decided to use the Cryptography API for better security and performance. They found existing solutions using the crypto library from node, Math.random, or nested loops and conditionals to be unsuitable. The author wanted to use the getRandomValues() function from the Cryptography API and ended up combining it with a "possible" chars approach to generate a 40-character string that is random enough, performs well, and can be easily encoded into a URL for submission to the identity provider.

Opinions

  • The author believes that authentication is not something to take chances with and wanted to find the best option for generating a random state.
  • The author found existing solutions using the crypto library from node, Math.random, or nested loops and conditionals to be unsuitable.
  • The author prefers using the Cryptography API and the getRandomValues() function for better security and performance.
  • The author combined the getRandomValues() function with a "possible" chars approach to generate a 40-character string that is random enough, performs well, and can be easily encoded into a URL.
  • The author believes that the 40-character strings produced by their code should be random enough and perform well for an OAuth2 implicit flow.
  • The author recommends trying out an AI service that provides the same performance and functions as ChatGPT Plus(GPT-4) but is more cost-effective.
  • The author does not provide any information on the specific AI service they recommend.

Generating Cryptographic Random State in JavaScript (in the Browser)

I need to generate some random state for an OAuth2 implicit flow for a JavaScript SPA. This “state” is passed to the identity provider, and then passed back after authentication to guard against XSS. Basically, I just need a string of random characters.

This state parameter is optional in OAuth2 implicit flow, and it only needs to be pseudo-random, but authentication isn’t something I like to take chances with, so I thought I’d look for the best option. I did a quick web search, as this seemed like the kind of thing that I’d find a perfect, best-practise, solution for on stack overflow, GitHub or similar. But, I had a few issues with the solutions I found:

  1. They used the crypto library from node, so were server-side solutions not intended for the browser, or,
  2. They used Math.random which I decided wasn’t suitable and I wanted to use the Javascript Cryptography API, or,
  3. They had nested loops and conditionals, which were either inefficient, or not declarative enough for my programming style, or,
  4. They produced a byte-string that didn’t encode easily in a URL.

Here was one of the implementations I liked, from an Angular OAuth2 library:

I liked the use of “possible” chars, but it uses Math.random() and I wanted to use getRandomValues() from the Cryptography API. I tried a couple of simple looking approaches to converting the bytes returned from getRandomValues but decided to combine it with the “possible” chars approach, and ended up with this:

The MDN docs for the Cryptography API states that:

To guarantee enough performance, implementations are not using a truly random number generator, but they are using a pseudo-random number generator seeded with a value with enough entropy. The PRNG used differs from one implementation to the other but is suitable for cryptographic usages. Implementations are also required to use a seed with enough entropy, like a system-level entropy source.

The 40 character strings that are produced by this code should be random enough, performance is OK, and they encode easily into an URL for submitting to the identify provider as part of an OAuth2 implicit flow.

JavaScript
Recommended from ReadMedium