package auth import ( "context" "errors" "fmt" "net/http" "time" session "github.com/go-session/session/v3" "github.com/golang-jwt/jwt/v5" ) type EasyAuth struct { client Auth JwtSecret []byte TimeUntilJWTExpired time.Duration } type UserClaims struct { jwt.RegisteredClaims User AuthentikUser } func NewEasyAuth(client Auth) (EasyAuth, error) { e := EasyAuth{} e.client = client e.JwtSecret = []byte("hsajedogö") e.TimeUntilJWTExpired = 120 * time.Minute return e, nil } func (e EasyAuth) CheckUser(w http.ResponseWriter, r *http.Request) (AuthentikUser, error) { user, con, err := e.GetUser(w, r) if err != nil { return AuthentikUser{}, err } if !con { return AuthentikUser{}, ErrUserNeedRedirect } return user, nil } func (e EasyAuth) Middelware(next http.HandlerFunc) http.HandlerFunc { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { user, err := e.CheckUser(w, r) if err != nil { if !errors.Is(err, ErrUserNeedRedirect) { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("panic doing auth: %v", err.Error()))) } return } ctx := context.WithValue(r.Context(), "user", user) next.ServeHTTP(w, r.WithContext(ctx)) // call ServeHTTP on the original handler }) } func (e EasyAuth) GetUser(w http.ResponseWriter, r *http.Request) (AuthentikUser, bool, error) { store, err := session.Start(context.Background(), w, r) if err != nil { return AuthentikUser{}, false, err } if r.Method == http.MethodGet { store.Set("url", r.URL.String()) store.Save() } jwtData, ok := store.Get("jwt") if !ok { e.redirectAuth(w, r) return AuthentikUser{}, false, nil } jwtString := fmt.Sprintf("%s", jwtData) parsedAccessToken, _ := jwt.ParseWithClaims(jwtString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) { return e.JwtSecret, nil }) if !parsedAccessToken.Valid { e.redirectAuth(w, r) return AuthentikUser{}, false, nil } claims := parsedAccessToken.Claims.(*UserClaims) return claims.User, true, nil } func (e EasyAuth) redirectAuth(w http.ResponseWriter, r *http.Request) error { redirectURL, err := e.client.GetAuthorizationURL("") if err != nil { return err } http.Redirect(w, r, redirectURL, http.StatusTemporaryRedirect) return nil } func (e EasyAuth) AuthHTTPHandler(w http.ResponseWriter, r *http.Request) { token, err := e.client.GetTokenFromCode(r.URL.Query().Get("code")) if err != nil { panic(err) // TODO: Deal with error } user := AuthentikUser{} err = e.client.GetUserInfo(token.AccessToken, &user) if err != nil { panic(err) // TODO: Deal with error } expired := time.Now().Add(e.TimeUntilJWTExpired) claims := UserClaims{} claims.Issuer = "EasyAuth" claims.Subject = user.Nickname claims.IssuedAt = jwt.NewNumericDate(time.Now()) claims.ExpiresAt = jwt.NewNumericDate(expired) claims.NotBefore = jwt.NewNumericDate(time.Now()) claims.User = user jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS512, claims) jwtString, err := jwtToken.SignedString(e.JwtSecret) if err != nil { panic(err) // TODO: Deal with error } store, err := session.Start(context.Background(), w, r) if err != nil { panic(err) // TODO: Deal with error } store.Set("jwt", jwtString) store.Save() redirectURL, ok := store.Get("url") redirectUrlString := "/" if ok { redirectUrlString = fmt.Sprintf("%s", redirectURL) } http.Redirect(w, r, redirectUrlString, http.StatusTemporaryRedirect) }