Skip to main content

Built and signed on GitHub Actions

A token format for APIs inspired by the GitHub's API token format.

This package works with Bun, Cloudflare Workers, Node.js, Deno, Browsers
JSR Score
100%
Published
4 months ago (2.1.0)

cybertoken CI CD npm badge

A token format inspired by GitHub's new API token format. Think of it as a standardized password format with some handy properties. Intended for API token and password generation.

What is this?

GitHub changed their token format a while back and explained the reasons in an insightful blog post[^1].

tl;dr:

  1. Having a defined format for secrets is good for automated secret scanning.
  2. Putting some prefix to a secret makes debugging easier when looking at some random token.
  3. Using _ instead of - is better for double-click text selection: abc_def vs abc-def.
  4. Using Base62[^2] instead of Base64 results in less encoding errors when passing the token somewhere.
  5. CRC32 checksum at the end of the token for faster offline syntactic check of a token (used as a heuristic, not for security).

These properties make this token format suitable for things like API tokens, which is what cybertoken is.

Usage

Install:

npm install cybertoken
import { createTokenGenerator } from "cybertoken";

const apiTokenGenerator = createTokenGenerator({
  prefixWithoutUnderscore: "contoso",
});

const token = apiTokenGenerator.generateToken();
// Securely hash `token` and save it in your database. Return `token` to the user once.

console.log(token);
// contoso_IvN2xEuHUDjQ3PNQgZkILWc7GUxpmThDD410NQxJalD5GjY

Bonus

You can also use cybertokens as passwords. If you use GitHub, you can set up a custom secret scanning pattern that will prevent anyone from pushing anything that looks like a cybertoken that your org uses.

For example, use this pattern for Cybertokens with the prefix contosopass:

contosopass_[0-9A-Za-z]{10,}

CLI Usage

The npm package also offers a command-line utility to generate tokens.

npm install -g cybertoken

Usage:

cybertoken <prefix>

# example:
cybertoken test
test_KOK5QxQr4GBGk97X8Ij5ZnyZO24kMIEiW1LdUYIqEj7A5Nv

You can also provide the token prefix via an env variable:

CYBERTOKEN_PREFIX=foo cybertoken

To make thing easier, you can put this in your .bashrc:

echo "export CYBERTOKEN_PREFIX=foo" >> ~/.bashrc

...and now you can just use cybertoken!

Anatomy

This is what a cybertoken consists of:

  prefix      base62(n-bytes + v + crc32(n-bytes + v))
┌────────┐ ┌──────────────────────────────────────────────┐
myapitoken_161YNJQOaoFoWLaoXeMVHYyrSLhGPOjSBYBtxY6V3GqFFZKV

Explanation:

  • n-bytes are n random bytes, but at least 21 (default: 22), generated by a cryptographically secure random source
  • v is a single byte containing the version of the cybertoken format used (currently, only 0x00)
  • The bytes are concatenated with the version and their CRC32 sum before base62 encoding
  • base62 alphabet used: 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

[^1]: GitHub's blog post covering this: https://github.blog/2021-04-05-behind-githubs-new-authentication-token-formats [^2]: More info in Base62: https://en.wikipedia.org/wiki/Base62

Built and signed on
GitHub Actions
View transparency log

Add Package

deno add @cybertoken/cybertoken

Import symbol

import * as mod from "@cybertoken/cybertoken";

Add Package

npx jsr add @cybertoken/cybertoken

Import symbol

import * as mod from "@cybertoken/cybertoken";

Add Package

yarn dlx jsr add @cybertoken/cybertoken

Import symbol

import * as mod from "@cybertoken/cybertoken";

Add Package

pnpm dlx jsr add @cybertoken/cybertoken

Import symbol

import * as mod from "@cybertoken/cybertoken";

Add Package

bunx jsr add @cybertoken/cybertoken

Import symbol

import * as mod from "@cybertoken/cybertoken";