Generating a Crypto Random String in Dart

Scott Brady
Scott Brady
Dart
Dart logo

To help a 10% project at work, the Rock Solid Knowledge IdentityServer team has been creating a basic OpenID Connect library for a Flutter application. After poking around in Dart over the weekend, I found that Dart did not have a straightforward way to create a cryptographically random string suitable for OAuth/OpenID Connect values such as state, nonce, or PKCE’s code challenge. So, in this article, I’m going to share a straightforward way to generate one. Skip to complete function.

Dart’s Random Number Generator

Luckily, Dart does have a cryptographically secure random number generator that we can use, found in the dart:math library. From what I can tell, this uses APIs on the underlying platform’s to achieve this (think window.crypto in the browser or a Windows API from the OS). If the platform does not have something suitable, a UnsupportedError will be thrown.

import 'dart:math';

var random = Random.secure();

var value = random.nextInt(1000000000);

However, a random integer does not achieve our goal of a random string. Sure, we could generate an integer that must be of a certain length, but a better approach would be to use this API to generate some random bytes.

Generating Random Bytes

To use our random number generator to create some random bytes, I used the following line of code:

var values = List<int>.generate(32, (i) => random.nextInt(256));

Here, we are generating 32 integers, each being anything from 0 to 256, giving us enough entropy for our purpose.

Now that we have the required amount of bytes, let’s get them ready for transport by Base64 URL encoding them using the library dart:convert:

import 'dart:convert';

base64Url.encode(values);

Dart’s implementation of Base64 URL encoding includes padding characters. Depending on how you are using this, you may need to strip these.

Complete Function

We can now combine all of this into a reusable method that takes in the required number of bytes, where the length is for the underlying bytes, not the resulting string.

import 'dart:convert';
import 'dart:math';

class utils {
    static final Random _random = Random.secure();

    static String CreateCryptoRandomString([int length = 32]) {
        var values = List<int>.generate(length, (i) => _random.nextInt(256));

        return base64Url.encode(values);
    }
}

This will generate you a value such as cghMOrBKfN97FbG8661ztXwvaS46gnjz_EAl5vYdzyA=.