apikey

package module
v0.0.0-...-0547182 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 27, 2025 License: MIT Imports: 8 Imported by: 0

README

go-api-key

This package provides a simple, extensible API key generator for Go, supporting custom random ID generators and token hashers.

Features

  • Generate API keys with a customizable prefix, short token, and long token.
  • Use your own random ID generator and token hasher, or use the secure defaults.
  • Parse and validate API keys.

Usage

  • Use the library to create an API key.
  • Store the ShortToken and the LongTokenHash in your database.
  • Send the LongToken to the user / client.

Installation

go get github.com/gunsluo/go-api-key

Example

package main

import (
	"fmt"
	"github.com/gunsluo/go-api-key"
)

func main() {
	// Create a generator with default secure random and Argon2id hasher
	gen, err := apikey.NewApiKeyGenerator(apikey.ApiKeyGeneratorOptions{
		TokenPrefix: "mycorp",
		// Optionally:
		// TokenIdGenerator:    &apikey.DefaultRandomBytesGenerator{},
		// TokenBytesGenerator: &apikey.DefaultRandomBytesGenerator{},
		// TokenHasher:         &apikey.Sha256Hasher{}, // or &apikey.Argon2IdHasher{}
	})
	if err != nil {
		panic(err)
	}

	// Generate a new API key
	key, err := gen.GenerateAPIKey()
	if err != nil {
		panic(err)
	}
	fmt.Println("API Key:", key.Token)

	// Parse and check
	parsed, err := gen.GetTokenComponents(key.Token)
	if err != nil {
		panic(err)
	}
	fmt.Printf("Short: %s, Long: %s, Hash: %s\n", parsed.ShortToken, parsed.LongToken, parsed.LongTokenHash)

	ok, err := gen.CheckAPIKey(key.Token, key.LongTokenHash)
	fmt.Println("Valid:", ok, "Error:", err)
}

Custom data

package main

import (
	"encoding/base64"
	"errors"
	"fmt"

	apikey "github.com/gunsluo/go-api-key"
)

func main() {
	// Create a generator with default secure random and Argon2id hasher
	gen, err := apikey.NewApiKeyGenerator(apikey.ApiKeyGeneratorOptions{
		TokenPrefix: "mycorp",
		// Optionally:
		TokenIdGenerator:    &CustomIdGenerator{},
		TokenBytesGenerator: &apikey.DefaultRandomBytesGenerator{},
		TokenHasher:         &apikey.Sha256Hasher{}, // or &apikey.Argon2IdHasher{}
	})
	if err != nil {
		panic(err)
	}

	// Generate a new API key
	key, err := gen.GenerateAPIKey(apikey.WithShortTokenData(
		"ChYzZDg4QWNjZDdDOHVVUnNkbVhuVHJWEgVsb2NhbA",
	))
	if err != nil {
		panic(err)
	}
	fmt.Println("API Key:", key.Token)
	fmt.Printf("API Key -> Short: %s, Long: %s, Hash: %s(%d)\n", key.ShortToken, key.LongToken, key.LongTokenHash, len(key.LongTokenHash))

	// Parse and check
	parsed, err := gen.GetTokenComponents(key.Token)
	if err != nil {
		panic(err)
	}
	fmt.Printf("Short: %s, Long: %s, Hash: %s(%d)\n", parsed.ShortToken, parsed.LongToken, parsed.LongTokenHash, len(parsed.LongTokenHash))

	ok, err := gen.CheckAPIKey(key.Token, key.LongTokenHash)
	fmt.Println("Valid:", ok, "Error:", err)
}

type CustomIdGenerator struct {
}

// Generate implements RandomBytesGenerator. The parameter n is ignored since
// the output length is determined by the subject and org ID.
func (c *CustomIdGenerator) Generate(data any) (string, error) {
	str, ok := data.(string)
	if !ok {
		return "", fmt.Errorf("data must be an *CompositeIdData for CustomIdGenerator")
	}

	if str == "" {
		return "", errors.New("str cannot be empty")
	}

	composite := fmt.Sprintf("custom::%s", str)
	encoded := base64.RawURLEncoding.EncodeToString([]byte(composite))
	return encoded, nil
}

Notes

  • The token prefix must be 1-8 characters, using only [a-zA-Z0-9_-] and must not contain the separator (#).
  • The default separator is #.
  • You can provide your own implementations of RandomBytesGenerator and Hasher for custom behavior/testing.

API Overview

Constructors
NewApiKeyGenerator
func NewApiKeyGenerator(opts ApiKeyGeneratorOptions) (*APIKeyGenerator, error)

Create a new API key generator. All options are set via the ApiKeyGeneratorOptions struct:

type ApiKeyGeneratorOptions struct {
	TokenPrefix         string // required, 1-8 chars, [a-zA-Z0-9_-], no separator
	TokenSeparator      rune   // optional, defaults to '#'
	TokenIdGenerator    RandomBytesGenerator // optional, defaults to secure random
	TokenBytesGenerator RandomBytesGenerator // optional, defaults to secure random
	TokenHasher         Hasher               // optional, defaults to SHA256
	ShortTokenBytes     int                  // optional, defaults to 16
	LongTokenBytes      int                  // optional, defaults to 64
}
Interfaces
RandomBytesGenerator
type RandomBytesGenerator interface {
	Generate(n int) (string, error)
}

Default: DefaultRandomBytesGenerator (crypto/rand, base64 URL encoding)

Hasher
type Hasher interface {
	Hash(token string) (string, error)
	Verify(token, hash string) bool
}

Default: Argon2IdHasher (Argon2id hash string). You can also use Sha256Hasher (SHA256 hex string).

Methods
(*APIKeyGenerator) GenerateAPIKey() (*APIKey, error)

Generate a new API key:

key, err := gen.GenerateAPIKey()
// key.ShortToken, key.LongToken, key.LongTokenHash, key.Token
(*APIKeyGenerator) GetTokenComponents(token string) (*APIKey, error)
(*APIKeyGenerator) CheckAPIKey(token, hash string) (bool, error)

Documentation

Overview

Package apikey provides functions to generate and parse Seam-style API keys with base64 encoding.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type APIKey

type APIKey struct {
	ShortToken    string
	LongToken     string
	LongTokenHash string
	Token         string
}

APIKey holds the components of a generated API key.

type APIKeyGenerator

type APIKeyGenerator struct {
	// contains filtered or unexported fields
}

func NewApiKeyGenerator

func NewApiKeyGenerator(opts ApiKeyGeneratorOptions) (*APIKeyGenerator, error)

NewApiKeyGenerator creates a new APIKeyGenerator using options. Id generator and hasher are optional.

func (*APIKeyGenerator) CheckAPIKey

func (a *APIKeyGenerator) CheckAPIKey(token, hash string) (bool, error)

CheckAPIKey verifies that the hash of the long token in the key matches the provided hash. At this point we expect the token to be in valid format e.g. extract via GetTokenComponents.

func (*APIKeyGenerator) GenerateAPIKey

func (a *APIKeyGenerator) GenerateAPIKey(opts ...APIKeyOption) (*APIKey, error)

GenerateAPIKey generates a new API key using the generator's prefix.

func (*APIKeyGenerator) GetTokenComponents

func (a *APIKeyGenerator) GetTokenComponents(token string) (*APIKey, error)

GetTokenComponents parses a full API key string into its components.

type APIKeyOption

type APIKeyOption func(*apiKeyOptions)

func WithLongTokenData

func WithLongTokenData(data any) APIKeyOption

func WithShortTokenData

func WithShortTokenData(data any) APIKeyOption

type ApiKeyGeneratorOptions

type ApiKeyGeneratorOptions struct {
	TokenPrefix         string
	TokenSeparator      rune // now a rune, not a string
	TokenIdGenerator    RandomBytesGenerator
	TokenBytesGenerator RandomBytesGenerator
	TokenHasher         Hasher
	ShortTokenBytes     int
	LongTokenBytes      int
}

type Argon2IdHasher

type Argon2IdHasher struct{}

Argon2IdHasher implements Hasher.

func (*Argon2IdHasher) Hash

func (d *Argon2IdHasher) Hash(longToken string) (string, error)

func (*Argon2IdHasher) Verify

func (d *Argon2IdHasher) Verify(token, hash string) bool

type DefaultRandomBytesGenerator

type DefaultRandomBytesGenerator struct{}

DefaultRandomBytesGenerator implements RandomIdGenerator using crypto/rand and base64.

func (*DefaultRandomBytesGenerator) Generate

func (d *DefaultRandomBytesGenerator) Generate(data any) (string, error)

type Hasher

type Hasher interface {
	Hash(token string) (string, error)
	Verify(token, hash string) bool
}

Hasher defines an interface for hashing a token string.

type RandomBytesGenerator

type RandomBytesGenerator interface {
	Generate(data any) (string, error)
}

RandomBytesGenerator defines an interface for generating random IDs as a string.

type Sha256Hasher

type Sha256Hasher struct{}

Sha256Hasher implements Hasher using SHA256.

func (*Sha256Hasher) Hash

func (d *Sha256Hasher) Hash(longToken string) (string, error)

func (*Sha256Hasher) Verify

func (d *Sha256Hasher) Verify(token, hash string) bool

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL