summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxengineering <me@xengineering.eu>2026-05-24 12:35:46 +0200
committerxengineering <me@xengineering.eu>2026-05-24 16:14:22 +0200
commit42d8ed4ccada1b9b3f063ca4ef68dff2844009eb (patch)
treecb4c8179b64940a27a30c4fa7e8ec1c9832bdf61
parent1362d9ff0a4498bbb793d4e919036abd4d7d31ae (diff)
downloadfinserv-42d8ed4ccada1b9b3f063ca4ef68dff2844009eb.tar
finserv-42d8ed4ccada1b9b3f063ca4ef68dff2844009eb.tar.zst
finserv-42d8ed4ccada1b9b3f063ca4ef68dff2844009eb.zip
Add authentication middlewareauth
This protects all parts of /api/* except the /api/register URL. This one must stay accessible to allow new users.
-rw-r--r--handlers.go38
1 files changed, 36 insertions, 2 deletions
diff --git a/handlers.go b/handlers.go
index f23171f..99b4eaf 100644
--- a/handlers.go
+++ b/handlers.go
@@ -6,15 +6,24 @@ import (
"io/fs"
"log"
"net/http"
+ "strings"
+)
+
+const (
+ COOKIE_NAME_TOKEN = `token`
)
//go:embed build/frontend/public
var frontendEmbed embed.FS
func init() {
- router.HandleFunc("/api/version", version)
+ // /api/registration must always be accessible without authentication
router.HandleFunc("/api/registration", registration).Methods("POST")
+ protected := router.PathPrefix("/api").Subrouter()
+ protected.Use(authentication)
+ protected.HandleFunc("/version", version)
+
// frontend must come last to make sure /api takes precedence
frontend, err := fs.Sub(frontendEmbed, "build/frontend/public")
if err != nil {
@@ -35,7 +44,7 @@ func registration(w http.ResponseWriter, r *http.Request) {
}
cookie := http.Cookie{
- Name: "token",
+ Name: COOKIE_NAME_TOKEN,
Value: token.Private(),
HttpOnly: true,
Secure: true,
@@ -46,3 +55,28 @@ func registration(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s\n", token.Public())
}
+
+func authentication(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ cookie, err := r.Cookie(COOKIE_NAME_TOKEN)
+ if err != nil {
+ http.Error(w, "No authentication cookie present.", http.StatusForbidden)
+ return
+ }
+
+ candidate, found := strings.CutPrefix(cookie.String(), COOKIE_NAME_TOKEN + "=")
+ if !found {
+ http.Error(w, "Unexpected cookie prefix.", http.StatusForbidden)
+ return
+ }
+
+ user := authenticate(candidate)
+ if user == nil {
+ http.Error(w, "Unknown authentication token.", http.StatusForbidden)
+ return
+ }
+
+ log.Printf("Authenticated user number %d\n", *user)
+ next.ServeHTTP(w, r)
+ })
+}