Package hawk supports to use Hawk authentication scheme.
About Hawk: https://github.com/hueniverse/hawk
go get github.com/hiyosi/hawk
simple client / server
// sample server
package main
import (
"fmt"
"time"
"github.com/hiyosi/hawk"
"net/http"
)
type credentialStore struct{}
func (c *credentialStore) GetCredential(id string) (*hawk.Credential, error) {
return &hawk.Credential{
ID: id,
Key: "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn",
Alg: hawk.SHA256,
}, nil
}
var testCredStore = &credentialStore{}
func hawkHandler(w http.ResponseWriter, r *http.Request) {
s := hawk.NewServer(testCredStore)
// authenticate client request
cred, err := s.Authenticate(r)
if err != nil {
w.Header().Set("WWW-Authenticate", "Hawk")
w.WriteHeader(401)
fmt.Println(err)
return
}
opt := &hawk.Option{
TimeStamp: time.Now().Unix(),
Ext: "response-specific",
}
// build server response header
h, _ := s.Header(r, cred, opt)
w.Header().Set("Server-Authorization", h)
w.WriteHeader(200)
w.Write([]byte("Hello, " + cred.ID))
}
func main() {
http.HandleFunc("/resource", hawkHandler)
http.ListenAndServe(":8080", nil)
}
// sample client
package main
import (
"fmt"
"time"
"github.com/hiyosi/hawk"
"io/ioutil"
"net/http"
)
func main() {
c := hawk.NewClient(
&hawk.Credential{
ID: "123456",
Key: "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn",
Alg: hawk.SHA256,
},
&hawk.Option{
TimeStamp: time.Now().Unix(),
Nonce: "3hOHpR",
Ext: "some-app-data",
},
)
// build request header
header, _ := c.Header("GET", "http://localhost:8080/resource")
req, _ := http.NewRequest("GET", "http://localhost:8080/resource", nil)
req.Header.Set("Authorization", header)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
// authenticate server response.
result, err := c.Authenticate(resp)
if err != nil {
fmt.Println("Server Authentication Failure")
}
fmt.Println("Server Authentication: ", result)
b, err := ioutil.ReadAll(resp.Body)
if err == nil {
fmt.Println(string(b))
}
}
build bewit parameter
// server
b := hawk.NewBewitConfig(
&hawk.Credential{
ID: "123456",
Key: "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn",
Alg: hawk.SHA256,
},
10 * time.Minute,
)
bewit := b.GetBewit("http://localhost:8080/temp/resource", nil)
fmt.Println(bewit)
authenticate bewit parameter
// server
func hawkBewitHandler(w http.ResponseWriter, r *http.Request) {
s := hawk.NewServer(testCredStore)
cred, err := s.AuthenticateBewit(r)
if err != nil {
w.Header().Set("WWW-Authenticate", "Hawk")
w.WriteHeader(401)
fmt.Println(err)
return
}
w.WriteHeader(200)
w.Write([]byte("Access Allow, " + cred.ID))
}
if behind a proxy, you can use an another header field or custom hostname.
- get host-name by specified header name.
s := hawk.NewServer(testCredStore)
s.AuthOption = &hawk.AuthOption{
CustomHostNameHeader: "X-Forwarded-Host",
}
- or specified hostname value yourself
s := hawk.NewServer(testCredStore)
s.AuthOption = &hawk.AuthOption{
CustomHostPort: "b.example.com:8888",
}
See godoc for further documentation
- Fork (https://github.com/hiyosi/hawk/fork)
- Create a feature branch
- Commit your changes
- Rebase your local changes against the master branch
- Run test suite with the
go test ./...
command and confirm that it passes - Run
gofmt -s
- Create new Pull Request