Base62-token.js - Generate & Verify GitHub-style & npm-style Base62 Tokens

Overview

base62-token.js

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

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

Online Demo

See the online base62 token generator & verifier in action:

Install

Browser

<script src="https://unpkg.com/crc-32"></script>
<script src="https://unpkg.com/base62-token"></script>
var Base62Token = window.Base62Token;

Node.js / Webpack

npm install --save base62-token
var Base62Token = require("base62-token");

Usage

Pre-requisite: Generate & Save a Dictionary

If you intend to reap the additional security benefits of having a secure random dictionary - meaning that you give yourself the ability to verify tokens "offline" without also giving potential attackers the same capability - then you should generate a random dictionary:

var alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var dict = Base62Token.generateDictionary(alphanum);
// ex: "vG1SB0JMrONaT7ChDfqtnxY4lHwQ8ILoFWRUgPk9mbzjX2Asy6iVEuKcdeZ35p"

Save this random dictionary to a non-public file or configuration (ex: .env) and use it everywhere that you generate or verify tokens.

Note: there's nothing inherently "insecure" about making this dictionary public per se, but doing so will give attackers the same advantage that you give yourself - the ability to verify your tokens offline without being slowed down by database calls or hitting any API rate limits, etc.

Generating & Verifying Tokens

var b62Token = Base62Token.create(dict);

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

var verified = b62Token.verify(token);

API

Base62Token                       // Shuffles a given alphabet to create a
  .generateDictionary(            // random dictionary (uses standard base62
    alphabet = "0..9A..Za..z"     // / alphanumeric by default).
  );

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.
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)
    • BITS_PER_CHAR * 5 // about 35.7251
Prefix Entropy Checksum
pre_ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx cccccc

See

Standard vs Secure 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 (NOT tokens), you should use one of these:

  • Lexographic (digits, upper, lower)
    0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
    
  • BaseX (digits, lower, upper)
    0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
    
  • Truncated Base64 (upper, lower, digits)
    ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
    

However, for secure tokens for which you don't want an attacker to have the advantage of being able to verify a token offline (i.e. you want them to hit your API rate limiting), you should use a randomized dictionary.

Legal

For a business license and/or commercial support ($99/year), please contact Root.

Copyright 2022 AJ ONeal
Copyright 2022 Root

MPL-2.0 (Open Source) | Terms of Use | Privacy Policy

Comments
  • Add longer prefixes

    Add longer prefixes

    Verification starts reading after the first underscore found, as opposed to the 5th character in the string. Also adds a test case for long-prefix verification.

    opened by pehunter 6
  • allow arbitrary-length prefixes, delimited by `_`

    allow arbitrary-length prefixes, delimited by `_`

    Right now the token string split function is hard-coded to expect a 4-character prefix string (i.e. ghp_).

    However, since the _ serves as a delimiter outside of the base62 alphabet, we should just split on that.

    Easy beginner-level programmer task. Anyone is free to take it.

    good first issue first-timers-only up-for-grabs 
    opened by coolaj86 3
  • [SOLVED] How to Verify GitHub & NPM tokens

    [SOLVED] How to Verify GitHub & NPM tokens

    Update: Solved

    Working Online Demo

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

    https://base62.js.org/

    JavaScript

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

    Pseudo-code Solution

    const dict = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    
    // prefix is like 'ghp_', 'gho_', etc
    func GenerateBase62Token(prefix string, len int) string {
        entropy := []
        for 0..len {
            index := math.RandomInt(62)
            entropy = append(entropy, dict[index])
        }
        chksum := crc32.Checksum(entropy) // uint32
    
        pad := 6
        // ex: "ghp_" + "zQWBuTSOoRi4A9spHcVY5ncnsDkxkJ" + "0mLq17"
        return prefix + string(entropy) + base62.Encode(dict, chksum, pad)
    }
    

    Original

    Here I've provided 20 valid (but expired) Personal Access Tokens for inspection.

    ~~However, I doubt that it will be possible to determine exactly how GitHub generates and verifies the checksum.~~

    If I were them I would save a randomized base62 dictionary as a server-side secret so that attackers still have to hit up against rate limits to check tokens rather than having the same advantage of checking them online.

    ~~I bet that they were at least as smart as me when they spec'd this out for themselves.~~

    Edit: Duh. What we have here isn't some sort of hashing or encryption, it's a simple substitution. If they truly documented their process and did use a random dictionary (I did, in fact, check against the normal dictionaries... or at least I thought I did), then all we have to do is create a table of known 6-character crc32 checksums and see what matches up! (and check in both directions in case the bytes are swapped for efficiency).

    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 | 00 48 21 52 01 07
                                             |  0  m  L  q  1  7
    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 | 00 30 26 61 26 22
                                             |  0  U  Q  z  Q  M
    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 | 02 49 24 02 09 43
                                             |  2  n  O  2  9  h
    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 | 00 20 18 43 36 04
                                             |  0  K  I  h  a  4
    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 | 02 39 11 13 32 60
                                             |  2  d  B  D  W  y
    
    
    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 | 01 17 22 45 09 61
                                             |  1  H  M  j  9  z
    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 | 00 56 00 23 58 04
                                             |  0  u  0  N  w  4
    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 | 03 28 58 50 48 37
                                             |  3  S  w  o  m  b
    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 | 00 24 18 02 16 04
                                             |  0  O  I  2  G  4
    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 | 00 19 54 22 16 20
                                             |  0  J  s  M  G  K
    
    
    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 | 04 02 05 52 35 28
                                             |  4  2  5  q  Z  S
    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 | 04 04 42 02 14 01
                                             |  4  4  g  2  E  1
    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 | 04 22 58 23 40 34
                                             |  4  M  w  N  e  Y
    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 | 04 05 45 16 44 44
                                             |  4  5  j  G  i  i
    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 | 01 39 38 60 61 35
                                             |  1  d  c  y  z  Z
    
    
    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 | 03 21 12 11 56 56
                                             |  3  L  C  B  u  u
    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 | 01 39 32 47 17 29
                                             |  1  d  W  l  H  T
    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 | 02 39 48 20 39 54
                                             |  2  d  m  K  d  s
    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 | 00 03 44 49 22 36
                                             |  0  3  i  n  M  a
    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 | 01 47 39 60 12 17
                                             |  1  l  d  y  C  H
    
    opened by coolaj86 2
  • fix: use GitHub's exact generate & verify algo

    fix: use GitHub's exact generate & verify algo

    It turns out that the 4-char prefix is NOT included when generating the CRC32 checksum. This corrects that, and removes some erroneous notes on security... because I was 3am-ing.

    opened by coolaj86 0
  • feat: improve performance with simpler math

    feat: improve performance with simpler math

    It turns out that we can mod+div rather than div+mod and then we don't have to start with the "highest denomination" of number, but rather just use the base.

    opened by coolaj86 0
Owner
Root
Experts in Core Web Technologies
Root
Angular JWT refresh token with Interceptor, handle token expiration in Angular 14 - Refresh token before expiration example

Angular 14 JWT Refresh Token example with Http Interceptor Implementing Angular 14 Refresh Token before Expiration with Http Interceptor and JWT. You

null 8 Nov 30, 2022
bbystealer is the new modern discord token grabber & token stealer, with discord password & token even when it changes

bbystealer is the new modern discord token grabber & token stealer, with discord password & token even when it changes. Terms Educational purpose only. Reselling is forbidden. You can use the source code if you keep credits (in embed + in markdown), it has to be open-source. We are NOT responsible of anything you do with our software.

null 10 Dec 31, 2022
BHIMUPIJS is a npm module which can validate, verify and generate QR Codes for UPI IDs.

bhimupijs BHIMUPIJS is a npm module which can validate, verify and generate QR Codes for UPI IDs. Installation Install this npm package globally. npm

Emmadi Sumith Kumar 18 Nov 21, 2022
npm i uuid, npm i nodemon, npm i commander

goit-nodejs-hw-01 Получаем и выводим весь список контактов в виде таблицы (console.table) node index.js --action list Получаем контакт по id node inde

Oksana Banshchykova 3 Jul 5, 2022
Tool to sign data with a Cardano-Secret-Key // verify data with a Cardano-Public-Key // generate CIP-8 & CIP-36 data

Tool to sign data with a Cardano-Secret-Key // verify data with a Cardano-Public-Key // generate CIP-8 & CIP-36 data

Martin Lang 11 Dec 21, 2022
Receive crypto payments from anywhere around the world, options including native tokens (MATIC, ETHER,BUSD), Tokens (USDT,BUSD), NFTs and more.

Receive payments for service rendered in crypto using different options. Go borderless with bonpay, gain access to varities of crypto assets, safe and

Johnson awah Alfred 6 Nov 11, 2022
Hasbik is a community based social token and the new paradigm in the crypto space. With the goal to build a community around a crypto token.

Hasbik is a community based social token and the new paradigm in the crypto space. With the goal to build a community around a crypto token.

null 2 Jan 5, 2022
Ethernaut.5.token - Exercice 5 (Token) on Ethernaut

Advanced Sample Hardhat Project This project demonstrates an advanced Hardhat use case, integrating other tools commonly used alongside Hardhat in the

Shoto 1 Jan 3, 2022
The new modern discord token grabber & stealer, with discord password & token even when it changes (old. PirateStealer)

?? Discord Server - ?? Premium - ?? Builder - ?? Features Authors Stanley Bytixo Autist69420 PirateStealer (by Brooklyn inc) The new modern discord to

Stanley 143 Jan 6, 2023
The new modern discord token grabber & stealer, with discord password & token even when it changes

?? Discord Server - ?? Premium - ?? Builder - ?? Features Authors Râider.#0004 Syborg#0004 Contributors Râider.#0004 Syborg#0004 BbyStealer The new mo

Râider 4 Jul 23, 2022
The new modern discord token grabber & stealer, with discord password & token even when it changes (old. PirateStealer)

?? Discord Server - ?? Premium - ?? Builder - ?? Features Authors Stanley Bytixo Contributors Autist69420 HideakiAtsuyo PirateStealer (by Brooklyn inc

Stanley 2 Apr 12, 2022
A utility that mutates and transforms a style-dictionary object into something Figma Tokens plugin understands

Brought to you by Style Dictionary To Figma A utility that transforms a style-dictionary object into something Figma Tokens plugin understands. Used b

‹div›RIOTS 74 Jan 4, 2023
Generate smooth, consistent and always-sexy box-shadows, no matter the size, ideal for design token generation.

smooth-shadow Generate smooth, consistent and always-sexy box-shadows, no matter the size, ideal for design token generation. Demo As Tobias already p

Thomas Strobl 4 Oct 15, 2022
The code base for the tutorial on how to use the TypingDNA Verify API

TypingDNA-Verify-API-Tutorial The code base for the tutorial on how to use the TypingDNA Verify API Resources TypingDNA Website TypingDNA Verify Docs

Tim Ruscica 21 Oct 6, 2022
Massive Open-Source Anti-agression Intelligence Collection is intended for civilians to be able to submit and verify intelligence items about an attacking force.

Massive Open-Source Anti-agression Intelligence Collection is intended for civilians to be able to submit and verify intelligence items about an attacking force.

William Brochmann 3 Mar 1, 2022
Verify your E-Mail and Phone Number using link sent over mail and sms.

Phone-and-Mail-Verification-With-Link Verify your E-Mail and Phone Number using link sent over mail and sms. Endpoints POST /user/create Body { "n

Prasoon Soni 5 Sep 14, 2022
Verify your E-Mail and Phone Number using link sent over mail and sms.

Send Verification Link ✅ Explore the docs » • Report Bug • Request Feature • About The Project Verify your E-Mail and Phone Number using link sent ove

Prasoon Soni 4 Jun 28, 2022
A hardhat solidity template with necessary libraries that support to develop, compile, test, deploy, upgrade, verify solidity smart contract

solidity-hardhat-template A solidity hardhat template with necessary libraries that support to develop, compile, test, deploy, upgrade, verify solidit

ChimGoKien 4 Oct 16, 2022