package main import ( "context" "fmt" "html/template" "net/http" "github.com/gorilla/mux" "github.com/zitadel/oidc/v2/pkg/op" ) const ( queryAuthRequestID = "authRequestID" ) var ( loginTmpl, _ = template.New("login").Parse(` Login

{{.Error}}

`) ) type login struct { authenticate authenticate router *mux.Router callback func(context.Context, string) string } func NewLogin(authenticate authenticate, callback func(context.Context, string) string, issuerInterceptor *op.IssuerInterceptor) *login { l := &login{ authenticate: authenticate, callback: callback, } l.createRouter(issuerInterceptor) return l } func (l *login) createRouter(issuerInterceptor *op.IssuerInterceptor) { l.router = mux.NewRouter() l.router.Path("/username").Methods("GET").HandlerFunc(l.loginHandler) l.router.Path("/username").Methods("POST").HandlerFunc(issuerInterceptor.HandlerFunc(l.checkLoginHandler)) } type authenticate interface { CheckUsernamePassword(ctx context.Context, username, password, id string) error } func (l *login) loginHandler(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { http.Error(w, fmt.Sprintf("cannot parse form:%s", err), http.StatusInternalServerError) return } //the oidc package will pass the id of the auth request as query parameter //we will use this id through the login process and therefore pass it to the login page renderLogin(w, r.FormValue(queryAuthRequestID), nil) } func renderLogin(w http.ResponseWriter, id string, err error) { var errMsg string if err != nil { errMsg = err.Error() } data := &struct { ID string Error string }{ ID: id, Error: errMsg, } err = loginTmpl.Execute(w, data) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } func (l *login) checkLoginHandler(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { http.Error(w, fmt.Sprintf("cannot parse form:%s", err), http.StatusInternalServerError) return } username := r.FormValue("username") password := r.FormValue("password") id := r.FormValue("id") err = l.authenticate.CheckUsernamePassword(r.Context(), username, password, id) if err != nil { renderLogin(w, id, err) return } http.Redirect(w, r, l.callback(r.Context(), id), http.StatusFound) }