75 lines
1.9 KiB
Go
75 lines
1.9 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"time"
|
|
|
|
"messenger/internal/auth"
|
|
)
|
|
|
|
const (
|
|
accessCookieName = "messenger_access"
|
|
refreshCookieName = "messenger_refresh"
|
|
accessTTL = 15 * time.Minute
|
|
refreshTTL = 30 * 24 * time.Hour
|
|
)
|
|
|
|
type ctxKey string
|
|
|
|
// ctxKeyUserID is the context key carrying the authenticated user ID.
|
|
const ctxKeyUserID ctxKey = "messenger.userID"
|
|
|
|
func userIDFrom(ctx context.Context) (int64, bool) {
|
|
id, ok := ctx.Value(ctxKeyUserID).(int64)
|
|
return id, ok
|
|
}
|
|
|
|
func withUserID(ctx context.Context, userID int64) context.Context {
|
|
return context.WithValue(ctx, ctxKeyUserID, userID)
|
|
}
|
|
|
|
// requireAuth parses the access-token cookie and injects the user ID
|
|
// into the request context.
|
|
func requireAuth(tm *auth.TokenManager, next http.HandlerFunc) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
cookie, err := r.Cookie(accessCookieName)
|
|
if err != nil {
|
|
writeError(w, http.StatusUnauthorized, "missing access token")
|
|
return
|
|
}
|
|
userID, err := tm.ParseAccessToken(cookie.Value)
|
|
if err != nil {
|
|
writeError(w, http.StatusUnauthorized, "invalid access token")
|
|
return
|
|
}
|
|
next(w, r.WithContext(withUserID(r.Context(), userID)))
|
|
}
|
|
}
|
|
|
|
func setAuthCookies(w http.ResponseWriter, accessToken, refreshToken string, secure bool) {
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: accessCookieName,
|
|
Value: accessToken,
|
|
Path: "/",
|
|
HttpOnly: true,
|
|
Secure: secure,
|
|
SameSite: http.SameSiteLaxMode,
|
|
MaxAge: int(accessTTL.Seconds()),
|
|
})
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: refreshCookieName,
|
|
Value: refreshToken,
|
|
Path: "/",
|
|
HttpOnly: true,
|
|
Secure: secure,
|
|
SameSite: http.SameSiteLaxMode,
|
|
MaxAge: int(refreshTTL.Seconds()),
|
|
})
|
|
}
|
|
|
|
func clearAuthCookies(w http.ResponseWriter) {
|
|
http.SetCookie(w, &http.Cookie{Name: accessCookieName, Path: "/", MaxAge: -1})
|
|
http.SetCookie(w, &http.Cookie{Name: refreshCookieName, Path: "/", MaxAge: -1})
|
|
}
|