package main import ( "crypto/rand" "math/big" "strings" ) // tokenAlphabet is deliberately letters and digits only, with no punctuation. // // This token is typed by hand into a phone. A base64url token looks stronger and is worse in // practice: the leading "-" of one generated token was eaten by `adb shell input text` treating // it as a flag, and "-" and "_" are both buried behind a modifier on a phone keyboard. 32 // characters of alphanumeric is ~165 bits, which is not the weak link here. const tokenAlphabet = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789" // tokenLength is 32 characters, grouped into fours by the caller when it prints them. const tokenLength = 32 // generateToken makes a fresh API token. // // From crypto/rand: this is the only thing between the open internet and a private library. // The alphabet omits l, I, 1, O and 0 so a token read off a screen cannot be mistyped into a // different valid-looking one. func generateToken() (string, error) { limit := big.NewInt(int64(len(tokenAlphabet))) var out strings.Builder for i := 0; i < tokenLength; i++ { n, err := rand.Int(rand.Reader, limit) if err != nil { return "", err } out.WriteByte(tokenAlphabet[n.Int64()]) } return out.String(), nil }