An open API service indexing awesome lists of open source software.

https://github.com/therootcompany/base62-token.js

Generate & Verify GitHub-style & npm-style Base62 Tokens
https://github.com/therootcompany/base62-token.js

base62 base62-encoding github-tokens-generator npm-tokens-generator security

Last synced: 7 months ago
JSON representation

Generate & Verify GitHub-style & npm-style Base62 Tokens

Awesome Lists containing this project

README

          

# [base62-token.js](https://github.com/therootcompany/base62-token.js)

Generate & Verify [GitHub-style][gh-tokens] & [npm-style][npm-tokens]
Base62 Tokens

[gh-tokens]:
https://github.blog/2021-04-05-behind-githubs-new-authentication-token-formats/
[npm-tokens]:
https://github.blog/2021-09-23-announcing-npms-new-access-token-format/

Works in Vanilla JS (Browsers), Node.js, and Webpack.

# [Online Demo](https://therootcompany.github.io/base62-token.js/)

See the online Base62 token generator & verifier in action:

-

# Install

## Browser

```html

```

```js
var Base62Token = window.Base62Token;
```

## Node.js / Webpack

```bash
npm install --save base62-token
```

```js
var Base62Token = require("base62-token");
```

# Usage

```js
var dict = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var b62Token = Base62Token.create(dict);

var token = b62Token.generate("abc_", 30);
var verified = b62Token.verify(token);
```

# API

```txt
Base62Token.generateDictionary(); // Return the Lexographic (a.k.a. GMP)
// Base62 dictionary.

Base62Token.create(dictionary); // Creates a token generator and verifier
// 'dictionary' is any 62-char alphabet.
// Returns a generator / verifier instance.

b62Token.generate(prefix, length); // Returns token string.
b62Token.verify(token); // Returns true / false.
```

```txt
Base62Token.BITS_PER_CHARACTER // 5.954196310386876
// For reference: Base64 is an even 6

Base62Token.calcMinChars(bitlen); // calculate the minimum number of chars
// needed to guarantee the target entropy.
// ex: 173-bit entropy needs 30 chars

Base62Token.calcMinBits(charlen); // calculate the minimum entropy guaranteed
// by the given number of characters
// ex: 30 chars guarantees 178-bit entropy.

Base62Token.checksum(dict, str); // generates an (unsigned) CRC-32 checksum
// for the given string (where each char is
// treated as a single byte).
// Returns the Base62 encoded unsigned int.

Base62Token.encode(dict, n, pad); // encode a 32-bit int (i.e. CRC-32 checksum)
// as Base62 in the given dictionary, with a
// default pad of 6 (guarantees 32-bits).
```

# Base62 Token Spec

## GitHub Token Breakdown

The 40-character tokens are broken down into 3 consecutive parts:

`pre_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcccccc`

- **Prefix**: 4-char (ex: `ghx_`)
- **Entropy**: 30-char (178-bits + leading 0 padding)
- `BITS_PER_CHAR = Math.log(62) / Math.log(2) // about 5.9541`
- `BITS_PER_CHAR * 30 // about 178.6258`
- **Checksum**: 6-char CRC32 (32-bits, 4 bytes, 6 base62 characters)
- (of entropy-only, not prefix)
- `BITS_PER_CHAR * 5 // about 35.7251`

| Prefix | Entropy | Checksum |
| -----: | :----------------------------- | :------- |
| pre\_ | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | cccccc |

See

- https://github.blog/2021-04-05-behind-githubs-new-authentication-token-formats/
- https://github.blog/changelog/2021-09-23-npm-has-a-new-access-token-format/

## Pseudocode

```go
const DICT = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
const PREFIX_LEN = 4
const CHECKSUM_LEN = 6

func GenerateBase62Token(prefix string, len int) string {
entropy := []string{}
for 0..len {
index := math.RandomInt(62) // 0..61
char := DICT[index]
entropy = append(entropy, char)
}
chksum := crc32.Checksum(entropy) // uint32

pad := CHECKSUM_LEN
chksum62 := base62.Encode(DICT, chksum, pad)

// ex: "ghp_" + "zQWBuTSOoRi4A9spHcVY5ncnsDkxkJ" + "0mLq17"
return prefix + string(entropy) + chksum62
}

func VerifyBase62Token(token string) bool {
// prefix is not used
entropy := token[PREFIX_LEN:len(token)-CHECKSUM_LEN]
chksum := base62.Decode(DICT, token[len(token)-CHECKSUM_LEN:]) // uint32

return crc32.Checksum(entropy) == chksum
}
```

## Standard Base62 Dictionaries

There are 3 widely-used, generic Base62 dictionaries, all of which are based on
the alphanumeric character set (i.e. 0-9, A-Z, a-z).

For general encoding and decoding, you should use one of these:

- Lexographic (digits, upper, lower)
```txt
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
```
- BaseX (digits, lower, upper)
```txt
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
```
- Truncated Base64 (upper, lower, digits)
```txt
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
```

GitHub and NPM use the Lexographic (a.k.a. GMP) Base62 alphabet.

# Legal

For a business license and/or commercial support ($99/year), please contact
[Root](https://therootcompany.com/contact/).

Copyright 2022 [AJ ONeal](https://coolaj86.com) \
Copyright 2022 [Root](https://therootcompany.com)

MPL-2.0 (Open Source) | [Terms of Use](https://therootcompany.com/legal/#terms)
| [Privacy Policy](https://therootcompany.com/legal/#privacy)