Implementing the OIDC logout endpoint & UI
When using Ory OAuth2 and OpenID Connect, by default the logout operation is handled by the Ory Account Experience. Alternatively, you can customize the logout experience by implementing a custom logout endpoint using the Ory SDK.
This document shows how to implement your own logout endpoint and customize the logout UI.
OpenID Connect logout overview
OpenID Connect defines two types of logout mechanisms: back-channel logout and front-channel logout.
- Back-channel logout is initiated by the identity provider (IdP) and is a server-to-server call.
- Front-channel logout, is initiated by the client and is a client-to-server call.
Customize logout experience
To customize the logout experience, you must implement a custom logout endpoint that can handle back-channel and front-channel 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.
Check out the reference implementation of this endpoint provided by Ory Hydra. Click here to view the code on GitHub.
The reference implementation includes the necessary code to handle back-channel and front-channel 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 back-channel and front-channel logout requests, as well as redirects the user to the homepage after logout.
Mermaid diagram
The following diagram illustrates the flow of a logout request: