logout endpoint for generic oidc provider (#968)

This commit is contained in:
Michael Quigley
2025-08-05 11:55:28 -04:00
parent 4881ac5fba
commit 059e594a80
3 changed files with 62 additions and 6 deletions

View File

@ -217,7 +217,7 @@ func (c *githubConfigurer) configure() error {
fmt.Sprintf("https://api.github.com/applications/%s/token", c.githubCfg.ClientId),
strings.NewReader(fmt.Sprintf(`{"access_token":"%s"}`, accessToken)))
if err != nil {
logrus.Errorf("error creating token delete request for '%v': %v", claims.Email, err)
logrus.Errorf("error creating access token delete request for '%v': %v", claims.Email, err)
proxyUi.WriteUnauthorized(w)
return
}
@ -227,16 +227,16 @@ func (c *githubConfigurer) configure() error {
resp, err := http.DefaultClient.Do(req)
if err != nil {
logrus.Errorf("error invoking token delete request for '%v': %v", claims.Email, err)
logrus.Errorf("error invoking access token delete request for '%v': %v", claims.Email, err)
proxyUi.WriteUnauthorized(w)
return
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusNoContent {
logrus.Infof("revoked github token for '%v'", claims.Email)
logrus.Infof("revoked github access token for '%v'", claims.Email)
} else {
logrus.Errorf("token revocation failed with status: %v", resp.StatusCode)
logrus.Errorf("access token revocation failed with status: %v", resp.StatusCode)
proxyUi.WriteUnauthorized(w)
return
}

View File

@ -200,12 +200,12 @@ func (c *googleConfigurer) configure() error {
if resp.StatusCode == http.StatusOK {
logrus.Infof("revoked google token for '%v'", claims.Email)
} else {
logrus.Errorf("token revocation failed with status: %v", resp.StatusCode)
logrus.Errorf("access token revocation failed with status: %v", resp.StatusCode)
proxyUi.WriteUnauthorized(w)
return
}
} else {
logrus.Errorf("unable to revoke token for '%v': %v", claims.Email, err)
logrus.Errorf("unable to revoke access token for '%v': %v", claims.Email, err)
proxyUi.WriteUnauthorized(w)
return
}

View File

@ -226,6 +226,62 @@ func (c *oidcConfigurer) configure() error {
}
http.Handle(fmt.Sprintf("/%v/auth/callback", c.oidcCfg.Name), rp.CodeExchangeHandler(rp.UserinfoCallback(login), provider))
logout := func(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie(c.cfg.CookieName)
if err == nil {
tkn, err := jwt.ParseWithClaims(cookie.Value, &zrokClaims{}, func(t *jwt.Token) (interface{}, error) {
return signingKey, nil
})
if err == nil {
claims := tkn.Claims.(*zrokClaims)
if claims.Provider == c.oidcCfg.Name {
accessToken, err := decryptToken(claims.AccessToken, encryptionKey)
if err == nil {
if err := rp.RevokeToken(context.Background(), provider, accessToken, "access_token"); err == nil {
logrus.Infof("revoked access token for '%v'", claims.Email)
} else {
logrus.Errorf("access token revocation failed: %v", err)
proxyUi.WriteUnauthorized(w)
return
}
} else {
logrus.Errorf("unable to decrypt access token for '%v': %v", claims.Email, err)
proxyUi.WriteUnauthorized(w)
return
}
} else {
logrus.Errorf("expected provider name '%v' got '%v'", c.oidcCfg.Name, claims.Email)
proxyUi.WriteUnauthorized(w)
return
}
} else {
logrus.Errorf("invalid jwt; unable to parse: %v", err)
proxyUi.WriteUnauthorized(w)
return
}
} else {
logrus.Errorf("error getting cookie '%v': %v", c.cfg.CookieName, err)
proxyUi.WriteUnauthorized(w)
return
}
http.SetCookie(w, &http.Cookie{
Name: c.cfg.CookieName,
Value: "",
MaxAge: -1,
Domain: c.cfg.CookieDomain,
Path: "/",
HttpOnly: true,
})
redirectURL := r.URL.Query().Get("redirect_url")
if redirectURL == "" {
redirectURL = fmt.Sprintf("%s/%s/login", c.cfg.EndpointUrl, c.oidcCfg.Name)
}
http.Redirect(w, r, redirectURL, http.StatusFound)
}
http.HandleFunc(fmt.Sprintf("/%v/logout", c.oidcCfg.Name), logout)
logrus.Infof("configured oidc provider at '/%v'", c.oidcCfg.Name)
return nil