diff --git a/TODO.md b/TODO.md
index 2277257..d6d72d7 100644
--- a/TODO.md
+++ b/TODO.md
@@ -30,7 +30,7 @@
- [x] Authentication System
- [x] Persistent logins across server restarts
- [x] User login
- - [ ] User logout
+ - [x] User logout
- [ ] Role-based access (admin, staff)
- [x] Password hashing
- [ ] CSRF Protection
diff --git a/internal/auth/auth.go b/internal/auth/auth.go
index 3dc20b6..10dce25 100644
--- a/internal/auth/auth.go
+++ b/internal/auth/auth.go
@@ -43,6 +43,7 @@ func (a *Authenticator) Middleware(in http.Handler) http.Handler {
handler := http.NewServeMux()
handler.HandleFunc("GET /login", getLogin)
handler.HandleFunc("POST /login", a.login)
+ handler.HandleFunc("GET /logout", a.logout)
handler.Handle("/", a.ensureAuth(in))
return handler
}
diff --git a/internal/auth/session.go b/internal/auth/session.go
index f4afa1c..6add9dc 100644
--- a/internal/auth/session.go
+++ b/internal/auth/session.go
@@ -50,3 +50,26 @@ func (a *Authenticator) login(w http.ResponseWriter, r *http.Request) {
http.SetCookie(w, &cookie)
http.Redirect(w, r, "/", http.StatusFound)
}
+
+func (a *Authenticator) logout(w http.ResponseWriter, r *http.Request) {
+ var cookie http.Cookie
+ cookie.Name = "token"
+ cookie.Value = "nil"
+ cookie.HttpOnly = true
+ cookie.SameSite = http.SameSiteStrictMode
+ cookie.Path = "/"
+ http.SetCookie(w, &cookie)
+ http.Redirect(w, r, "/", http.StatusFound)
+ c, err := r.Cookie("token")
+ if err != nil {
+ return
+ }
+ _, ok := a.sessions[c.Value]
+ if !ok {
+ return
+ }
+ fmt.Println("removing session")
+ delete(a.sessions, c.Value)
+ err = a.s.RevokeSession(c.Value)
+ fmt.Println(err)
+}
diff --git a/internal/server/templates/layout/nav.gohtml b/internal/server/templates/layout/nav.gohtml
index b6fd88d..6c7c96e 100644
--- a/internal/server/templates/layout/nav.gohtml
+++ b/internal/server/templates/layout/nav.gohtml
@@ -3,4 +3,5 @@
New order
All Cakes
New Cake
+Logout
{{end}}
diff --git a/internal/store/session.go b/internal/store/session.go
index b34c551..76d5b8d 100644
--- a/internal/store/session.go
+++ b/internal/store/session.go
@@ -12,6 +12,12 @@ func (s *Store) AddSession(token, userName string, expiration time.Time) error {
return err
}
+func (s *Store) RevokeSession(token string) error {
+ query := "delete from session where token = ?;"
+ _, err := s.db.Exec(query, token)
+ return err
+}
+
func (s *Store) CleanSessions() error {
now := time.Now().Format("2006-01-02 15:04")
query := "delete from session where expiration < ?;"