http_auth

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: May 1, 2025 License: BSD-3-Clause Imports: 7 Imported by: 0

README

HTTP Auth* Headers Parser Go Reference

A compliant-enough implementation to parse HTTP WWW-Authenticate & Authorization headers with 0 dependencies

This implementation tries to be compliant-enough (to the extent of my skills) with the grammars defined in RFC 7230 § 3.2.6 & RFC 7235 § 2.1 with regards to processing the values of the HTTP Authorization headers.

Usage

When consuming challenge headers (www-authenticate, proxy-authenticate)
package main

import (
	"fmt"
	http_auth "github.com/josegomezr/go-http-auth-challenge"
)

func main() {
	// what a server would respond
	wwwAuthenticateHeader := `Bearer realm="https://auth.docker.io/token",service="registry.docker.io"`

	// Get the list of defined challenges
	challenges, err := http_auth.ParseChallenges(wwwAuthenticateHeader, true)
	if err != nil {
		panic(fmt.Sprintf("Error parsing challenges: %s", err))
	}

	// To accomodate for multiple challenges on a single header, the return type
	// is a slice of challenges, most of the world only uses one at a time, it up
	// for consumers to take this decision and use the first challenge if they
	// see it fit.
	for _, challenge := range challenges {
		switch challenge.Scheme {
		case "Basic":
			fmt.Println("Scheme: Basic")
			/* do some stuff with auth basic */
			// ...
			realm, found := challenge.Realm()
			if found {
				fmt.Println("- realm:", realm)
			}
		case "Bearer":
			fmt.Println("Scheme: Bearer")
			/* do some stuff with auth basic */
			// ...

			realm, found := challenge.Realm()
			if found {
				fmt.Println("- realm:", realm)
			}
			service, found := challenge.GetParam("service")
			if found {
				fmt.Println("- service:", service)
			}
			fmt.Printf("- all-params: %v\n", challenge.Params)
		default:
			panic(fmt.Sprintf("Unknown challenge scheme: %s", challenge.Scheme))
		}
	}
}
When consuming authorization headers (authentication, proxy-authorization)
package main

import (
	"fmt"
	http_auth "github.com/josegomezr/go-http-auth-challenge"
)

func main() {
	// what a server would respond
	authorizationHeader := `Bearer dG9rZW4=,keyId=abc,username=foo`

	// Get the list of defined challenges
	challenge, err := http_auth.ParseAuthorization(authorizationHeader, true)
	if err != nil {
		panic(fmt.Sprintf("Error parsing authorization header: %s", err))
	}

	fmt.Println("Scheme: ", challenge.Scheme)
	// The convention here is that tokens (not auth-params) are saved in order
	// as string indexes. If it's too cumbersome, i'll refactor it.
	value0, found := challenge.GetParam("0")
	if found {
		fmt.Println("- value0:", value0)
	}
	fmt.Printf("- all-params: %v\n", challenge.Params)
}

Take a look at the example_*.go files for more usage tips.

Documentation

Overview

A compliant-enough implementation to parse HTTP WWW-Authenticate & Authorization headers

Index

Examples

Constants

View Source
const TokenParameterName = ":TOKEN68:"

The value for the Token of this particular Authorization.

Using a delimiter for the name is a nice trick to avoid accidental parameter overwrites when parsing headers. It's impossible for an authentication parameter to have a delimiter in the key as per grammar: <token, see [RFC7230], Section 3.2.6>

Variables

This section is empty.

Functions

This section is empty.

Types

type Authorization

type Authorization = Challenge

Challenge & Authorization are effectively the same type

func ParseAuthorization

func ParseAuthorization(input string) (Authorization, error)
Example (Newstyle)

Inspect the authorization header sent by client.

package main

import (
	"fmt"
	http_auth "github.com/josegomezr/go-http-auth-challenge"
	"log"
)

func main() {
	authorizationHeader := `Bearer userId=alpha,token="ObscureTokenHere="`
	authorization, err := http_auth.ParseAuthorization(authorizationHeader)
	if err != nil {
		log.Fatalf("Error parsing challenge: %s", err)
	}

	fmt.Println("Scheme:", authorization.Scheme)
	userId, foundUserId := authorization.GetParam("userId")
	token, foundToken := authorization.GetParam("token")
	fmt.Printf("- userId (found=%v): %s\n", foundUserId, userId)
	fmt.Printf("- token  (found=%v): %s\n", foundToken, token)
}
Example (Simple)

Inspect the bearer token sent by client.

package main

import (
	"fmt"
	http_auth "github.com/josegomezr/go-http-auth-challenge"
	"log"
)

func main() {
	authorizationHeader := `Bearer ObscureTokenHere=`
	authorization, err := http_auth.ParseAuthorization(authorizationHeader)
	if err != nil {
		log.Fatalf("Error parsing challenge: %s", err)
	}

	fmt.Println("Scheme:", authorization.Scheme)
	token, found := authorization.GetTokenParam()
	fmt.Printf("- token (found=%v): %s\n", found, token)
}

type Challenge

type Challenge struct {
	Scheme string
	Params Params
}

Represents an HTTP Challenge as per RFC 7235 § 2.1

func NewChallenge added in v0.3.0

func NewChallenge() Challenge

Initialize a new Challenge

func ParseChallenges

func ParseChallenges(input string) ([]Challenge, error)
Example (InspectChallenges)

Inspect the challenges sent by a server.

package main

import (
	"fmt"
	http_auth "github.com/josegomezr/go-http-auth-challenge"
	"log"
)

func main() {
	wwwAuthenticateHeader := `Basic realm="Your pet's name", Bearer service="postal", Fax number=1234`
	challenges, err := http_auth.ParseChallenges(wwwAuthenticateHeader)
	if err != nil {
		log.Fatalf("Error parsing challenge: %s", err)
	}

	for _, challenge := range challenges {
		switch challenge.Scheme {
		case "Basic":
			fmt.Println("Scheme: Basic")
			realm, found := challenge.Realm()
			if found {
				fmt.Println("- realm:", realm)
			}
		case "Bearer":
			fmt.Println("Scheme: Bearer")
			service, found := challenge.Params["service"]
			if found {
				fmt.Println("- service:", service)
			}
			fmt.Printf("- all-params: %v\n", challenge.Params)
		default:
			fmt.Printf("Unknown challenge scheme: %s - %v\n", challenge.Scheme, challenge.Params)
		}
	}
}

func (*Challenge) GetParam

func (c *Challenge) GetParam(key string) (string, bool)

Get an authentication parameter by name

func (*Challenge) GetTokenParam added in v0.3.0

func (c *Challenge) GetTokenParam() (string, bool)

Get the default authentication parameter (token)

func (*Challenge) IsEmpty

func (c *Challenge) IsEmpty() bool

Checks if a Challenge is empty (Either name is empty or has no params)

func (*Challenge) Realm

func (c *Challenge) Realm() (string, bool)

Shortcut for Challenge.GetParam("realm")

type Params added in v0.3.0

type Params = map[string]string

Representation of Authorization Parameters

Jump to

Keyboard shortcuts

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