https://github.com/josegomezr/go-http-auth-challenge
Pure go library for parsing HTTP authentication headers described in RFC 7235 & 7230
https://github.com/josegomezr/go-http-auth-challenge
authentication authorization golang http library
Last synced: 30 days ago
JSON representation
Pure go library for parsing HTTP authentication headers described in RFC 7235 & 7230
- Host: GitHub
- URL: https://github.com/josegomezr/go-http-auth-challenge
- Owner: josegomezr
- License: bsd-3-clause
- Created: 2025-04-04T11:27:28.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2025-05-01T11:16:04.000Z (about 1 year ago)
- Last Synced: 2025-05-01T12:25:55.766Z (about 1 year ago)
- Topics: authentication, authorization, golang, http, library
- Language: Go
- Homepage:
- Size: 43.9 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Authors: AUTHORS
Awesome Lists containing this project
README
HTTP Auth* Headers Parser [](https://pkg.go.dev/github.com/josegomezr/go-http-auth-challenge)
===
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](https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6) & [RFC 7235 § 2.1](https://datatracker.ietf.org/doc/html/rfc7235#section-2.1) with regards
to processing the values of the HTTP Authorization headers.
Usage
---
### When consuming challenge headers (`www-authenticate`, `proxy-authenticate`)
```go
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`)
```go
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.