From 65a69b585d696545292d2a33c69801fd166e921c Mon Sep 17 00:00:00 2001 From: matt Date: Wed, 28 Oct 2026 21:40:23 -0700 Subject: [PATCH] OIDC test - test jumbojett oidc round two 1 --- web/.env | 9 ----- web/auth.php | 27 ++++++++++++++ web/callback.php | 51 ++++++++++++-------------- web/composer.json | 5 +-- web/config.php | 34 ++++++++---------- web/index.php | 36 ++++++++++--------- web/login.php | 30 ---------------- web/logout.php | 28 --------------- web/src/OIDC.php | 91 ----------------------------------------------- 9 files changed, 85 insertions(+), 226 deletions(-) delete mode 100644 web/.env create mode 100644 web/auth.php delete mode 100644 web/login.php delete mode 100644 web/logout.php delete mode 100644 web/src/OIDC.php diff --git a/web/.env b/web/.env deleted file mode 100644 index 675657e..0000000 --- a/web/.env +++ /dev/null @@ -1,9 +0,0 @@ -OIDC_CLIENT_ID=fitness-oidc -OIDC_CLIENT_SECRET=egebuqzZfVnjjBG9JDQ8tjW3TzV9gJurvT7qfB6c2SX2nPBNeaGycDfx4788QzJd -OIDC_REDIRECT_URI=https://fitness.matt-cloud.com/pgapi/auth/oidc/callback -OIDC_AUTH_ENDPOINT=https://auth.matt-cloud.com/oidc/auth -OIDC_TOKEN_ENDPOINT=https://auth.matt-cloud.com/oidc/token -OIDC_USERINFO_ENDPOINT=https://auth.matt-cloud.com/oidc/userinfo -OIDC_LOGOUT_ENDPOINT=https://auth.matt-cloud.com/logout -# Optional: the default redirect after logout -OIDC_POST_LOGOUT_REDIRECT_URI=https://fitness.matt-cloud.com/ \ No newline at end of file diff --git a/web/auth.php b/web/auth.php new file mode 100644 index 0000000..a16cfec --- /dev/null +++ b/web/auth.php @@ -0,0 +1,27 @@ +setRedirectURL($config['redirect_uri']); + +// Tell it which scopes we want +$oidc->addScope($config['scopes']); + +// The OIDC flow we’ll use +$oidc->setResponseTypes([$config['response_type']]); + +// Optional: for local development you can relax TLS validation +// $oidc->setVerifyHost(false); +// $oidc->setVerifyPeer(false); + +$oidc->authenticate(); // This automatically redirects to Authelia \ No newline at end of file diff --git a/web/callback.php b/web/callback.php index bf058e1..7e667a3 100644 --- a/web/callback.php +++ b/web/callback.php @@ -1,40 +1,33 @@ setRedirectURL('https://fitness.matt-cloud.com/pgapi/auth/oidc/callback'); +$oidc->setRedirectURL($config['redirect_uri']); +$oidc->addScope($config['scopes']); +$oidc->setResponseTypes([$config['response_type']]); -try { - // Finish the auth flow – exchanges the code, validates the ID‑token, fetches userinfo - $oidc->authenticate(); +// This will read the `code` query parameter, fetch the tokens +// and validate everything. +$oidc->authenticate(); - // $oidc->idToken is a JWT object; you can cast to array if needed - $idToken = $oidc->idToken; - // Userinfo (includes groups because you requested the `groups` scope) - $userInfo = $oidc->getUserInfo(); // or $oidc->requestUserInfo('email') +// Fetch the OpenID Connect userinfo claims +$claims = $oidc->requestUserInfo(); // → stdClass with the claims - // Store what you need in the session - $_SESSION['user'] = [ - 'id_token' => $oidc->idToken, // JWT string - 'access_token'=> $oidc->accessToken, // opaque or JWT - 'refresh_token'=> $oidc->refreshToken, - 'expires_in' => $oidc->expiresIn, - 'claims' => (array)$idToken, // decoded claims - 'userinfo' => $userInfo, - ]; -} catch (Exception $e) { - http_response_code(500); - echo "Authentication failed: " . $e->getMessage(); - exit; -} +// Store what we need in the PHP session +$_SESSION['authenticated'] = true; +$_SESSION['name'] = $claims->name ?? $claims->given_name ?? $claims->family_name ?? ''; +$_SESSION['email'] = $claims->email ?? ''; +$_SESSION['groups'] = $claims->groups ?? []; -// Redirect to the site’s landing page -header('Location: /'); +// Redirect back to the home page +header('Location: ../'); exit; \ No newline at end of file diff --git a/web/composer.json b/web/composer.json index c08ba4a..ddab54b 100644 --- a/web/composer.json +++ b/web/composer.json @@ -1,8 +1,5 @@ { "require": { - "jumbojett/openid-connect-php": "^2.4", - "vlucas/phpdotenv": "^5.4", - "guzzlehttp/guzzle": "^7.0", - "firebase/php-jwt": "^7.0" + "jumbojett/openid-connect-php": "^1.0" } } \ No newline at end of file diff --git a/web/config.php b/web/config.php index 7495633..940909e 100644 --- a/web/config.php +++ b/web/config.php @@ -1,23 +1,19 @@ 'https://auth.matt-cloud.com', // <-- change if you run locally -session_start(); + // Client (your application) credentials + 'client_id' => 'fitness-oidc', + 'client_secret' => 'egebuqzZfVnjjBG9JDQ8tjW3TzV9gJurvT7qfB6c2SX2nPBNeaGycDfx4788QzJd', -/** - * Load environment variables. If you don't use phpdotenv, - * copy the values from .env directly here. - */ -$dotenv = Dotenv\Dotenv::createImmutable(__DIR__); -$dotenv->load(); + // The callback URL **must** match exactly what is in Authelia + 'redirect_uri' => 'https://fitness.matt-cloud.com/pgapi/auth/oidc/callback', -/** - * Basic OIDC configuration – keep all secrets out of source‑control. - */ -define('OIDC_CLIENT_ID', getenv('OIDC_CLIENT_ID')); -define('OIDC_CLIENT_SECRET', getenv('OIDC_CLIENT_SECRET')); -define('OIDC_REDIRECT_URI', getenv('OIDC_REDIRECT_URI')); -define('OIDC_AUTH_ENDPOINT', getenv('OIDC_AUTH_ENDPOINT')); -define('OIDC_TOKEN_ENDPOINT', getenv('OIDC_TOKEN_ENDPOINT')); -define('OIDC_USERINFO_ENDPOINT', getenv('OIDC_USERINFO_ENDPOINT')); -define('OIDC_LOGOUT_ENDPOINT', getenv('OIDC_LOGOUT_ENDPOINT')); -define('OIDC_POST_LOGOUT_REDIRECT_URI', getenv('OIDC_POST_LOGOUT_REDIRECT_URI')); \ No newline at end of file + // Scopes we want – Authelia already provides “openid”, “profile”, “email”, “groups” + 'scopes' => ['openid', 'profile', 'email', 'groups'], + + // Response type & grant type + 'response_type' => 'code', +]; \ No newline at end of file diff --git a/web/index.php b/web/index.php index fb74276..d48fae8 100644 --- a/web/index.php +++ b/web/index.php @@ -1,19 +1,23 @@ - - -Fitness - OIDC Demo - - - - -

Welcome, !

-

Email:

-

Groups:

-

JWT claims:

+$config = require __DIR__ . '/../config.php'; - - - - \ No newline at end of file +if (!isset($_SESSION['authenticated'])) { + // User not logged in – show a login button + echo '

Welcome to the demo

'; + echo '

Login with Authelia SSO

'; + exit; +} + +// The user is logged in – display the attributes +$name = $_SESSION['name'] ?? 'unknown'; +$email = $_SESSION['email'] ?? 'unknown'; +$groups = $_SESSION['groups'] ?? []; + +echo '

Logged in as ' . htmlspecialchars($name) . '

'; +echo ''; + +echo '

Logout

'; \ No newline at end of file diff --git a/web/login.php b/web/login.php deleted file mode 100644 index a5637d1..0000000 --- a/web/login.php +++ /dev/null @@ -1,30 +0,0 @@ -setVerifyPeer(false); // <-- DO NOT USE IN PRODUCTION - -// PKCE – optional but recommended for public clients -$oidc->setCodeChallengeMethod('S256'); - -// Tell the client where to land after Auth -$oidc->setRedirectURL('https://fitness.matt-cloud.com/pgapi/auth/oidc/callback'); - -// Optional: hard‑code the discovery URL -$oidc->setDiscoveryEndpoint('https://auth.matt-cloud.com/.well-known/openid-configuration'); - -try { - $oidc->authenticate(); // sends 302 → Authelia -} catch (Exception $e) { - http_response_code(500); - echo 'Login failed: ' . $e->getMessage(); - exit; -} \ No newline at end of file diff --git a/web/logout.php b/web/logout.php deleted file mode 100644 index de98a0e..0000000 --- a/web/logout.php +++ /dev/null @@ -1,28 +0,0 @@ -getLogoutEndpoint(); // e.g. https://auth.matt-cloud.com/logout - -// Include the post‑logout redirect URI -$logoutUrl .= '?post_logout_redirect_uri=' . urlencode('https://fitness.matt-cloud.com/'); - -// Optionally pass the ID‑token hint so the OP can immediately terminate the session -if (isset($_SESSION['user']['id_token'])) { - $logoutUrl .= '&id_token_hint=' . urlencode($_SESSION['user']['id_token']); -} - -// Destroy the local session first -session_destroy(); - -// Redirect the browser -header('Location: ' . $logoutUrl); -exit; \ No newline at end of file diff --git a/web/src/OIDC.php b/web/src/OIDC.php deleted file mode 100644 index c1e47b2..0000000 --- a/web/src/OIDC.php +++ /dev/null @@ -1,91 +0,0 @@ -http = new Client(['http_errors' => false]); - } - - /** - * Build the Auth URL that redirects the user to Authelia. - */ - public function buildAuthUrl(string $state, string $nonce): string - { - $params = [ - 'response_type' => 'code', - 'client_id' => OIDC_CLIENT_ID, - 'redirect_uri' => OIDC_REDIRECT_URI, - 'scope' => 'openid profile email groups', - 'state' => $state, - 'nonce' => $nonce, - ]; - - return OIDC_AUTH_ENDPOINT . '?' . http_build_query($params); - } - - /** - * Exchange the Authorization Code for tokens. - */ - public function exchangeCode(string $code): array - { - $response = $this->http->post(OIDC_TOKEN_ENDPOINT, [ - 'auth' => [OIDC_CLIENT_ID, OIDC_CLIENT_SECRET], - 'form_params' => [ - 'grant_type' => 'authorization_code', - 'code' => $code, - 'redirect_uri' => OIDC_REDIRECT_URI, - ], - ]); - - if ($response->getStatusCode() !== 200) { - throw new \RuntimeException('Token endpoint returned ' . $response->getStatusCode()); - } - - return json_decode((string)$response->getBody(), true, 512, JSON_THROW_ON_ERROR); - } - - /** - * Call /userinfo with the access token. - */ - public function getUserInfo(string $accessToken): array - { - $response = $this->http->get(OIDC_USERINFO_ENDPOINT, [ - 'headers' => [ - 'Authorization' => 'Bearer ' . $accessToken, - ], - ]); - - if ($response->getStatusCode() !== 200) { - throw new \RuntimeException('Userinfo endpoint returned ' . $response->getStatusCode()); - } - - return json_decode((string)$response->getBody(), true, 512, JSON_THROW_ON_ERROR); - } - - /** - * Validate the ID Token (minimal validation for demo purposes). - */ - public function validateIDToken(string $idToken, string $nonce): array - { - // Authelia uses RS256 by default, but your config says "none". - // We'll decode without verification if alg is "none". - $decoded = JWT::decode($idToken, new Key('', ''), ['none', 'RS256']); - - // Check nonce matches what we stored in session. - if ($decoded->nonce !== $nonce) { - throw new \RuntimeException('Invalid nonce'); - } - - return (array)$decoded; - } -} \ No newline at end of file