Skip to content

feat: add API endpoint for retrieving OIDC logout URL #17015

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor(coderd): apply codersdk.OIDCLogoutResponse at success
  • Loading branch information
esifea committed Mar 25, 2025
commit c2c3ddfd8559220c3e3c72bf9dce46cb7c7d2924
35 changes: 20 additions & 15 deletions coderd/userauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,7 @@ func (api *API) postLogout(rw http.ResponseWriter, r *http.Request) {
// @Security CoderSessionToken
// @Produce json
// @Tags Users
// @Success 200 {object} map[string]string "Returns a map containing the OIDC logout URL"
// @Success 200 {object} codersdk.OIDCLogoutResponse "Returns a map containing the OIDC logout URL"
// @Router /users/oidc-logout [get]
func (api *API) userOIDCLogoutURL(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
Expand All @@ -766,6 +766,11 @@ func (api *API) userOIDCLogoutURL(rw http.ResponseWriter, r *http.Request) {
return
}

logger := api.Logger.Named(userAuthLoggerName)

// Default response: empty URL if OIDC logout is not supported
response := codersdk.OIDCLogoutResponse{URL: ""}

// Retrieve the user's OAuthAccessToken for logout
// nolint:gocritic // We only can get user link by user ID and login type with the system auth.
link, err := api.Database.GetUserLinkByUserIDLoginType(dbauthz.AsSystemRestricted(ctx),
Expand All @@ -774,16 +779,17 @@ func (api *API) userOIDCLogoutURL(rw http.ResponseWriter, r *http.Request) {
LoginType: user.LoginType,
})
if err != nil {
api.Logger.Error(ctx, "failed to retrieve OIDC user link", "error", err)
if xerrors.Is(err, sql.ErrNoRows) {
httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{
Message: "No OIDC link found for this user.",
})
} else {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Failed to retrieve user authentication data.",
})
logger.Warn(ctx, "no OIDC link found for this user")
httpapi.Write(ctx, rw, http.StatusOK, response)
return
}

logger.Error(ctx, "failed to retrieve OIDC user link", "error", err)
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Failed to retrieve user authentication data.",
Detail: err.Error(),
})
return
}

Expand All @@ -796,19 +802,18 @@ func (api *API) userOIDCLogoutURL(rw http.ResponseWriter, r *http.Request) {
logoutURI := dvOIDC.LogoutRedirectURI.Value()

if oidcEndpoint == "" {
api.Logger.Error(ctx, "missing OIDC logout endpoint")
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "OIDC configuration is missing.",
})
logger.Warn(ctx, "missing OIDC logout endpoint")
httpapi.Write(ctx, rw, http.StatusOK, response)
return
}

// Construct OIDC Logout URL
logoutURL, err := url.Parse(oidcEndpoint)
if err != nil {
api.Logger.Error(ctx, "failed to parse OIDC endpoint", "error", err)
logger.Error(ctx, "failed to parse OIDC endpoint", "error", err)
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Invalid OIDC endpoint.",
Detail: err.Error(),
})
return
}
Expand All @@ -829,7 +834,7 @@ func (api *API) userOIDCLogoutURL(rw http.ResponseWriter, r *http.Request) {
logoutURL.RawQuery = q.Encode()

// Return full logout URL
response := map[string]string{"oidc_logout_url": logoutURL.String()}
response.URL = logoutURL.String()
httpapi.Write(ctx, rw, http.StatusOK, response)
}

Expand Down