phpkeycloaklogout

Keycloak logout


I am new to Keycloak, but I have set up a Keycloak server, the installation, configuration, and access to my web application.

Authentication goes through a custom SPI for read-only access to a database managed by our web application. No proxy, just a web app using ExtJS and PHP on Apache2 with mod_auth_openid.

The problem — something I didn't think would be this complicated to me — is understanding what a logout is and how to do it with Keycloak.

Despite, I've already read some of the documentation and examples on the subject, a lot of them are new to me, I feel like I've tried everything, and I still don't understand the expected behavior.

I was deleting/clearing cookies, but it does not seem to be working with the Keycloak cookies (both in JS and PHP).

document.cookie.split(";").forEach(cookie => {
    document.cookie = cookie.replace(/^ +/, "")
    .replace(/=.*/, 
            "=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/");
});
foreach($_COOKIE as $name => $value) {
        setcookie($name, '', time()-3600, '/');
}
header("Location: /");

I'm looking forward to work with the logout URI : "https://1.1.1.1/realms/dev/protocol/openid-connect/logout"

I saw some example with what it seems to be a depreciated method to me, /auth/.

Whether I call it via POST or GET, manually through my browser or in my PHP, with or without parameters, it does not log the user out.

Here is the PHP code I am using to try the logout part:


$realm = "dev";
$keycloak_base_url = "https://1.1.1.1:8443";
$redirect_uri = "https://1.1.1.1/app/";
$client_id = "mySuperclient";
$client_secret = "mySuperSecret";


$refresh_token = $_SERVER['OIDC_refresh_token'];
$access_token = $_SERVER['OIDC_access_token'];
$logout_url = "$keycloak_base_url/realms/$realm/protocol/openid-connect/logout";

$data = [
    'client_id' => $client_id,
    'refresh_token' => $refresh_token,
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $logout_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curl_error = curl_error($ch);
curl_close($ch);

if ($http_code === 204) {
    echo "Successful! Redirecting...";
    header("Location: /app/");  
    exit();
} else {
    echo "Failed! HTTP Code: $http_code <br>";
    echo "<pre>" . htmlspecialchars($response) . "</pre><br>";
}

OS : Debian 12.9 PHP version: 8.2.26 Keycloak : 26.1.0 (bare metal install) mod-auth-openidc :2.4.12.3

I don't really know, but everything seems to be good, the client, scopes and redirect uris works, all that remains is the logout part...

EDIT1: The use of

header ("Location: $logout_url");

redirects me to a Keycloak logout confirmation page. Even with a manual validation, I still can access my web app without login.

I think I have to add some data to that logout redirect, but can't figure out what is necessary.


Solution

  • I think there is a misunderstanding how Open ID Connect works.

    To log out the User from your application, you have to destroy the session.

    In PHP you can do it with

    session_destroy();
    

    This will destroy the session in your application, or Resource Provider (RP), but not the user Session on Keycloak, the Identity Provider for your application.

    If you really want to log off the user from Keycloak, you have to redirect him to Logout End-Point of Keycloack immediately after destroying the local session, for example with:

    header ("Location: $logout_url");
    

    PS: The keycloak should be configured to accept logout requests too.