feat(example): add example server

This commit is contained in:
AJ ONeal 2022-05-09 13:35:47 -06:00
parent c529b415bc
commit 70b0af6796
No known key found for this signature in database
GPG Key ID: 562702827EF68D87
13 changed files with 224 additions and 6 deletions

19
.well-known/jwks.json Normal file
View File

@ -0,0 +1,19 @@
{
"keys": [
{
"crv": "P-256",
"kid": "tsb1m6h3xjp1HjXmJY_8pTtHxld5UvWxoPG9b2e_0aY",
"kty": "EC",
"use": "sig",
"x": "VSQ5P-nwzOMVYowySPF8-FFRTLGXfY611ErayGgM4cc",
"y": "qSVv69YEJdM7waa_w8wegsaFDZaFZNkRNV-2PUGXb_E"
},
{
"e": "AQAB",
"kid": "dS08lAcJu_zmqIFkBwbI7rgi4OGlaF3uugjs6NysFEY",
"kty": "RSA",
"n": "q0yq8t-8Sw9nAJQAbDhiUMtxD_OEHigOekZrcLR38JkagqUZlxYZNp1B7NXM8GTymtz3qKzxUoI-mmE9gHq2nyDN8Jc_DTe_jnNFPD_bAxo92Ii_jpT74_6PR7I92BBvw0-ecxKHScJlO2tD2l1hxyOwpJ52Gt3WuXp2Ezsd3_14boTU4Z3Wh7WFNStz-BBwl09KR8UmVz1_pifJMnDEDXsRMEorFEbSDlJoZLAQgjAEwEZdmecH256WANKGylk1m5PWIBA59FMNXdQZIN1e6Cc0knaqZJHLor1hzmfSjyxxhSck0xk0HccUFNskS9QMoX05IvupxcnMBVPXIQBstw",
"use": "sig"
}
]
}

View File

@ -0,0 +1,4 @@
{
"issuer": "https://therootcompany.github.io/libauth/",
"jwks_uri": "https://therootcompany.github.io/libauth/.well-known/jwks.json"
}

View File

@ -0,0 +1 @@
openid-configuration

View File

@ -1,6 +1,7 @@
# [libauth](https://git.rootprojects.org/root/libauth)
LibAuth for Go - A modern authentication framework that feels as light as a library.
LibAuth for Go - A modern authentication framework that feels as light as a
library.
[![godoc_button]][godoc]
@ -27,7 +28,7 @@ import (
func main() {
r := chi.NewRouter()
whitelist, err := keyfetch.NewWhitelist([]string{"https://accounts.google.com"})
whitelist, err := keyfetch.NewWhitelist([]string{"https://therootcompany.github.io/libauth/"})
if nil != err {
panic(err)
}
@ -53,11 +54,45 @@ func main() {
}
```
How to create a demo token with [keypairs][https://webinstall.dev/keypairs]:
```bash
my_key='./examples/privkey.ec.jwk.json'
my_claims='{
"iss": "https://therootcompany.github.io/libauth/",
"sub": "1",
"email_verified": false,
"email": "jo@example.com"
}'
keypairs sign \
--exp 1h \
"${my_key}" \
"${my_claims}" \
> jwt.txt
2> jws.json
```
How to pass an auth token:
```bash
curl -X POST http://localhost:3000/api/users/profile \
-H 'Authorization: Bearer <xxxx.yyyy.zzzz>' \
-H 'Content-Type: application/json' \
--raw-data '{ "foo": "bar" }'
pushd ./examples
go run ./server.go
```
```bash
my_token="$(cat ./examples/jwt.txt)"
curl -X POST http://localhost:3000/api/users/profile \
-H "Authorization: Bearer ${my_token}" \
-H 'Content-Type: application/json' \
--data-binary '{ "foo": "bar" }'
```
## Example OIDC Discovery URLs
- Demo:
<https://therootcompany.github.io/libauth/.well-known/openid-configuration>
- Auth0: <https://example.auth0.com/.well-known/openid-configuration>
- Okta: <https://example.okta.com/.well-known/openid-configuration>
- Google: <https://accounts.google.com/.well-known/openid-configuration>

8
examples/README.md Normal file
View File

@ -0,0 +1,8 @@
# Examples
These example RSA and ECDSA private keys can be validated against the demo site:
| Issuer | <https://therootcompany.github.io/libauth/> |
| :------------ | :-------------------------------------------------------------------------- |
| Discovery URL | <https://therootcompany.github.io/libauth/.well-known/openid-configuration> |
| JWKs URL | <https://therootcompany.github.io/libauth/.well-known/jwks.json> |

13
examples/generate-jwt.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/bash
keypairs sign \
--exp 87660h \
./examples/privkey.ec.jwk.json \
'{
"iss": "https://therootcompany.github.io/libauth/",
"sub": "1",
"email_verified": false,
"email": "jo@example.com"
}' \
> ./examples/jwt.txt \
2> ./examples/jws.json

9
examples/go.mod Normal file
View File

@ -0,0 +1,9 @@
module git.rootprojects.org/root/libauth/examples
go 1.18
require (
git.rootprojects.org/root/keypairs v0.6.5
git.rootprojects.org/root/libauth v0.1.0
github.com/go-chi/chi/v5 v5.0.7
)

6
examples/go.sum Normal file
View File

@ -0,0 +1,6 @@
git.rootprojects.org/root/keypairs v0.6.5 h1:sdRAQD/O/JBS8+ZxUewXnY+cjQVDNH3TmcS+KtANZqA=
git.rootprojects.org/root/keypairs v0.6.5/go.mod h1:WGI8PadOp+4LjUuI+wNlSwcJwFtY8L9XuNjuO3213HA=
git.rootprojects.org/root/libauth v0.1.0 h1:qM73YYBLByoFTJUXH2ZeUhJdLzY35t4jgNoUAyqH2QA=
git.rootprojects.org/root/libauth v0.1.0/go.mod h1:bbLDWn0w7I1VfOMP2DZU/t/H9Ln0mT61K+ELH4ievVM=
github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=

18
examples/jws.json Normal file
View File

@ -0,0 +1,18 @@
{
"claims": {
"email": "jo@example.com",
"email_verified": false,
"exp": 1967702403,
"iss": "https://therootcompany.github.io/libauth/",
"sub": "1"
},
"header": {
"alg": "ES256",
"kid": "tsb1m6h3xjp1HjXmJY_8pTtHxld5UvWxoPG9b2e_0aY",
"typ": "JWT"
},
"payload": "eyJlbWFpbCI6ImpvQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJleHAiOjE5Njc3MDI0MDMsImlzcyI6Imh0dHBzOi8vdGhlcm9vdGNvbXBhbnkuZ2l0aHViLmlvL2xpYmF1dGgvIiwic3ViIjoiMSJ9",
"protected": "eyJhbGciOiJFUzI1NiIsImtpZCI6InRzYjFtNmgzeGpwMUhqWG1KWV84cFR0SHhsZDVVdld4b1BHOWIyZV8wYVkiLCJ0eXAiOiJKV1QifQ",
"signature": "-vezm5OL5c4vlFvvj0Z4HAbX2nAAabO_37w5wMtnD2_OuzTDhM_4wRxzEZ5sdUIJ0rM7gGAv7B3CfGSibr0TJA"
}

1
examples/jwt.txt Normal file
View File

@ -0,0 +1 @@
eyJhbGciOiJFUzI1NiIsImtpZCI6InRzYjFtNmgzeGpwMUhqWG1KWV84cFR0SHhsZDVVdld4b1BHOWIyZV8wYVkiLCJ0eXAiOiJKV1QifQ.eyJlbWFpbCI6ImpvQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJleHAiOjE5Njc3MDI0MDMsImlzcyI6Imh0dHBzOi8vdGhlcm9vdGNvbXBhbnkuZ2l0aHViLmlvL2xpYmF1dGgvIiwic3ViIjoiMSJ9.-vezm5OL5c4vlFvvj0Z4HAbX2nAAabO_37w5wMtnD2_OuzTDhM_4wRxzEZ5sdUIJ0rM7gGAv7B3CfGSibr0TJA

View File

@ -0,0 +1,7 @@
{
"crv": "P-256",
"d": "xcwk5FI9QuCK7Ap-aRsjdaHQx6ckoXcgQQ_HQbarUWE",
"kty": "EC",
"x": "VSQ5P-nwzOMVYowySPF8-FFRTLGXfY611ErayGgM4cc",
"y": "qSVv69YEJdM7waa_w8wegsaFDZaFZNkRNV-2PUGXb_E"
}

View File

@ -0,0 +1,11 @@
{
"d": "d3iFUdcRcBhR8mlG0jOQ_mClfkaMwquVTVqH3JdBf6CIiM21R1a2Rwzuyctjn9YIDlJGuHHF7ZHBL9LaHh13-QvcFgymgQV8qFFk3Fx813EZ6UeWsk7eT2lfbNW3pFXyXPnOvNsTWDIogISTUl0GsOkHbgjGvn4yIDJ033y_nVP6MybnTS7Z-bNZj7YUo9srlTUxXLHd8U9r8b5UIWRCyWeOhsxNjiCCOEinmL6dISjKeubpoG6mbBxC7ptglINqVYHu9HxFfOqd-epbQw0Y5DGIvd6iyzbsfmx8DJwXoJ31oyiFMPdgO5kbZbwEDBCxnHBzxH8M3kfYmL5uYRfnYQ",
"dp": "YAJfR37hBBwaXct4qkY7_pM2hHRtUOwEAq6QiSB24ogWzq8ehPfIAE_Vu1NAPhMVZk_UPt9A8444pUDLGXpe1-Y66TSC9l6x0g4LhX44A0sc6Wh5Cpbjjr77aim5aVf1AyR-SiPkHNY4SGl_VbkBtk6JOTlww5QwDEdbvcl8ugs",
"dq": "qO8KbV5svwEAdbHiKt0iFts53PQiD1p-XkvAeV4TPJKYfEmkQPqnpfe6pjN-dnl0S_OwdajLvnU_qVXs0Gec8hJHBf6nBuU0DpIxUML1R-aBqnEPH6-tH8pYK-fD0qr20Qr8tkR8hKI5cthOS0wiqh9A7FC4AUZxLgWOFhs0VdE",
"e": "AQAB",
"kty": "RSA",
"n": "q0yq8t-8Sw9nAJQAbDhiUMtxD_OEHigOekZrcLR38JkagqUZlxYZNp1B7NXM8GTymtz3qKzxUoI-mmE9gHq2nyDN8Jc_DTe_jnNFPD_bAxo92Ii_jpT74_6PR7I92BBvw0-ecxKHScJlO2tD2l1hxyOwpJ52Gt3WuXp2Ezsd3_14boTU4Z3Wh7WFNStz-BBwl09KR8UmVz1_pifJMnDEDXsRMEorFEbSDlJoZLAQgjAEwEZdmecH256WANKGylk1m5PWIBA59FMNXdQZIN1e6Cc0knaqZJHLor1hzmfSjyxxhSck0xk0HccUFNskS9QMoX05IvupxcnMBVPXIQBstw",
"p": "wzVny5EpwoVF_ljD7mxVVk0gjWTfJ2lkXunb5HbpB_1XkY464kptA9WzSa_0kuSegUrcAPL3KrLPx2ZOT9y9Q5q2RLH4MSCm2uarRvYTiKt9LkIdPFH68iUrrt8wAMX4KXA13mwD-hPpdxNB_Dz1qWqaodW_X-zXLEntBv2tUXs",
"q": "4KUoRNx164BsU8mFRV9fs4ZUm2fR-Z_JxlUj04dOcu4YYxQNmiSSXDUcTxx3-s4gphh1EVBv52eQ9R7tmmu9EEPIMWWbgdG5FclawDbiUuFnH7MsPT71y6NKWoxUfnzBivLgsdymruYUmJltXvH27pPeZoZetuAzzQFfM25ctvU",
"qi": "GbOKVpISiuLNPYzTSfQv0pYDDKwtdxyRlSPwU-0rjuYdzsTI6p4QRIbb-8pdWDTuBhmOuB3NUGGPRmeLn8187Z1iTsRSy7bjWmwqcXfOtc22En7OfTUhaUn-p83u9-NpFyGIkB8smZ-kV_g3DEwxovWvvcF3bAajvQCNrbqsOLQ"
}

86
examples/server.go Normal file
View File

@ -0,0 +1,86 @@
package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
"strings"
"github.com/go-chi/chi/v5"
"git.rootprojects.org/root/keypairs/keyfetch"
"git.rootprojects.org/root/libauth"
"git.rootprojects.org/root/libauth/chiauth"
)
func main() {
r := chi.NewRouter()
whitelist, err := keyfetch.NewWhitelist([]string{"https://therootcompany.github.io/libauth/"})
if nil != err {
panic(err)
}
// Unauthenticated Routes
r.Group(func(r chi.Router) {
r.Post("/api/hello", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`{ "message": "Hello, World!" }`))
})
})
// Authenticated Routes
r.Group(func(r chi.Router) {
tokenVerifier := chiauth.NewTokenVerifier(chiauth.VerificationParams{
Issuers: whitelist,
Optional: true,
})
r.Use(tokenVerifier)
r.Post("/api/users/profile", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
jws, ok := ctx.Value(chiauth.JWSKey).(*libauth.JWS)
if !ok || !jws.Trusted {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
userID := jws.Claims["sub"].(string)
b, _ := json.MarshalIndent(struct {
UserID string `json:"user_id"`
}{
UserID: userID,
}, "", " ")
w.Write(append(b, '\n'))
})
})
// ...
bindAddr := ":3000"
fmt.Println("Listening on", bindAddr)
fmt.Println("")
fmt.Println("Try this:")
fmt.Println("")
fmt.Println("")
cwd, _ := os.Getwd()
fmt.Println(" pushd", cwd)
fmt.Println("")
fmt.Println(" my_jwt=\"$(cat ./jwt.txt)\"")
fmt.Println(
strings.Join(
[]string{
" curl -X POST http://localhost:3000/api/users/profile",
" -H \"Authorization: Bearer ${my_jwt}\"",
" -H 'Content-Type: application/json'",
" --data-binary '{ \"foo\": \"bar\" }'",
},
" \\\n",
),
)
fmt.Println("")
http.ListenAndServe(bindAddr, r)
}