Implementing the OIDC logout endpoint & UI
When using Ory OAuth2 and OpenID Connect, the default logout experience is the managed account experience. However, it's possible to customize the logout experience by implementing a custom logout endpoint using the Ory SDK. In this guide, we will walk through the steps of implementing your own logout endpoint and customizing the logout UI.
OpenID Connect logout overview
OpenID Connect defines two types of logout mechanisms: backchannel logout and frontchannel logout. Backchannel logout is initiated by the identity provider (IdP) and is a server-to-server call. Frontchannel logout, on the other hand, is initiated by the client and is a client-to-server call.
Customize logout experience
To customize the logout experience, we need to implement a custom logout endpoint that can handle backchannel and frontchannel logout requests. The Logout HTML Form can't be a Single Page App (Client-side browser application) or a Mobile App! There has to be a server-side component with access to an Ory API Key.
To get started, you can check out the reference implementation of this endpoint provided by Ory Hydra. The code is available on GitHub at https://github.com/ory/hydra-login-consent-node.
The reference implementation includes the necessary code to handle backchannel and frontchannel logout requests, as well as a basic UI for the logout page. However, you can customize the UI to fit your needs.
Code example
To implement your own logout endpoint using the Ory SDK, you can use the following code as a starting point:
import { Configuration, OAuth2Api } from "@ory/client"
import { Request, Response } from "express"
const ory = new OAuth2Api(
new Configuration({
basePath: `https://${process.env.ORY_PROJECT_SLUG}.projects.oryapis.com`,
accessToken: process.env.ORY_API_KEY,
}),
)
function allowLogout() {
// Dummy function - this returns true or false depending on user input.
return true
}
// Please note that this is an example implementation.
// In a production app, please add proper error handling.
export async function handleLogout(request: Request, response: Response) {
const challenge = request.query.logout_challenge.toString()
const { data: logoutRequest } = await ory.getOAuth2LogoutRequest({
logoutChallenge: challenge.toString(),
})
console.log(logoutRequest.subject) // more fields are available
// The user did not want to sign out from the given app.
if (!allowLogout()) {
await ory
.rejectOAuth2LogoutRequest({
logoutChallenge: challenge,
})
.then(() => {
// Do something - redirect somewhere, for example the default home page.
})
return
}
ory
.acceptOAuth2LogoutRequest({
logoutChallenge: challenge,
})
.then(({ data }) => response.redirect(data.redirect_to))
}
This code handles both backchannel and frontchannel logout requests, as well as redirects the user to the homepage after logout.
Mermaid diagram
The following Mermaid diagram illustrates the flow of a logout request: