Skip to content

Commit

Permalink
feat(webauthn): add user database (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
Darkness4 authored Jan 13, 2024
1 parent f14619a commit 3e052c3
Show file tree
Hide file tree
Showing 22 changed files with 1,701 additions and 219 deletions.
17 changes: 9 additions & 8 deletions auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import (
)

const (
tokenCookieKey = "session_token"
// TokenCookieKey is the key of the cookie stored in the context.
TokenCookieKey = "session_token"
)

type claimsContextKey struct{}
Expand Down Expand Up @@ -115,14 +116,14 @@ func (a *Auth) CallBack() http.HandlerFunc {
return
}

token, err := a.JWTSecret.GenerateToken(userID, userName)
token, err := a.JWTSecret.GenerateToken(userID, userName, strings.ToLower(p))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

cookie := &http.Cookie{
Name: tokenCookieKey,
Name: TokenCookieKey,
Value: token,
Path: "/",
Expires: time.Now().Add(jwt.ExpiresDuration),
Expand All @@ -136,7 +137,7 @@ func (a *Auth) CallBack() http.HandlerFunc {
// Logout removes session cookies and redirect to home.
func (a *Auth) Logout() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie(tokenCookieKey)
cookie, err := r.Cookie(TokenCookieKey)
if err != nil {
// Ignore error. Cookie doesn't exists.
http.Redirect(w, r, "/", http.StatusSeeOther)
Expand All @@ -154,7 +155,7 @@ func (a *Auth) Logout() http.HandlerFunc {
func (a *Auth) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Get the JWT token from the request header
cookie, err := r.Cookie(tokenCookieKey)
cookie, err := r.Cookie(TokenCookieKey)
if err != nil {
next.ServeHTTP(w, r)
return
Expand All @@ -169,13 +170,13 @@ func (a *Auth) Middleware(next http.Handler) http.Handler {
}

// Store the claims in the request context for further use
ctx := context.WithValue(r.Context(), claimsContextKey{}, claims)
ctx := context.WithValue(r.Context(), claimsContextKey{}, *claims)
next.ServeHTTP(w, r.WithContext(ctx))
})
}

// GetClaimsFromRequest is a helper function to fetch the JWT session token from an HTTP request.
func GetClaimsFromRequest(r *http.Request) (claims *jwt.Claims, ok bool) {
claims, ok = r.Context().Value(claimsContextKey{}).(*jwt.Claims)
func GetClaimsFromRequest(r *http.Request) (claims jwt.Claims, ok bool) {
claims, ok = r.Context().Value(claimsContextKey{}).(jwt.Claims)
return claims, ok
}
3 changes: 2 additions & 1 deletion auth/auth_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import (

// Config is the authentication configuration definition for the application.
type Config struct {
Providers []ProviderConfig `yaml:"providers"`
Providers []ProviderConfig `yaml:"providers"`
SelfHostUsers bool `yaml:"selfHostUsers"`
}

// ProviderConfig is the configuration of one provider to achieve the OAuth2 flow.
Expand Down
47 changes: 47 additions & 0 deletions auth/webauthn/session/webauthn_session_store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Package session handles the login/register sessions of webauthn.
package session

import (
"context"
"errors"

"github.com/go-webauthn/webauthn/webauthn"
)

// Store stores the login/registration session.
type Store interface {
Save(ctx context.Context, session *webauthn.SessionData) error
Get(ctx context.Context, userID []byte) (*webauthn.SessionData, error)
}

// ErrNotFound happens when the session is not found in the store.
var ErrNotFound = errors.New("not found in session store")

// StoreInMemory stores the login/registration session in-memory.
//
// In production, you should use a Redis or ETCD, or any distributed Key-Value database.
// Because of this, you cannot create replicas.
type StoreInMemory struct {
store map[string]*webauthn.SessionData
}

// NewInMemory instanciates a session store in memory.
func NewInMemory() Store {
return &StoreInMemory{
store: make(map[string]*webauthn.SessionData),
}
}

// Get the login or registration session.
func (s *StoreInMemory) Get(_ context.Context, userID []byte) (*webauthn.SessionData, error) {
if v, ok := s.store[string(userID)]; ok {
return v, nil
}
return nil, ErrNotFound
}

// Save the login or registration session.
func (s *StoreInMemory) Save(_ context.Context, session *webauthn.SessionData) error {
s.store[string(session.UserID)] = session
return nil
}
Loading

0 comments on commit 3e052c3

Please sign in to comment.