OidcClient.php 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. <?php
  2. /*
  3. * Copyright 2026 Alessandro Chiapparini <sprint_planer_web@chiapparini.org>
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * See the LICENSE file in the project root for the full license text.
  9. */
  10. declare(strict_types=1);
  11. namespace App\Auth;
  12. use Jumbojett\OpenIDConnectClient;
  13. use RuntimeException;
  14. /**
  15. * Thin factory around jumbojett/openid-connect-php configured for
  16. * Microsoft Entra ID (v2.0 endpoint) with Authorization Code + PKCE.
  17. *
  18. * Reads these env vars:
  19. * ENTRA_TENANT_ID
  20. * ENTRA_CLIENT_ID
  21. * ENTRA_CLIENT_SECRET
  22. * APP_BASE_URL
  23. */
  24. final class OidcClient
  25. {
  26. public static function create(): OpenIDConnectClient
  27. {
  28. $tenant = self::env('ENTRA_TENANT_ID');
  29. $clientId = self::env('ENTRA_CLIENT_ID');
  30. $clientSecret = self::env('ENTRA_CLIENT_SECRET');
  31. $baseUrl = rtrim(self::env('APP_BASE_URL'), '/');
  32. $issuer = "https://login.microsoftonline.com/{$tenant}/v2.0";
  33. $oidc = new OpenIDConnectClient($issuer, $clientId, $clientSecret);
  34. $oidc->setRedirectURL($baseUrl . '/auth/callback');
  35. $oidc->addScope(['openid', 'profile', 'email']);
  36. $oidc->setCodeChallengeMethod('S256'); // PKCE
  37. // Entra's userinfo endpoint doesn't return new info beyond the id_token
  38. // for our scopes; rely on verified claims to avoid the extra round trip.
  39. return $oidc;
  40. }
  41. public static function isConfigured(): bool
  42. {
  43. foreach (['ENTRA_TENANT_ID', 'ENTRA_CLIENT_ID', 'ENTRA_CLIENT_SECRET', 'APP_BASE_URL'] as $k) {
  44. $v = getenv($k);
  45. if (!is_string($v) || $v === '') {
  46. return false;
  47. }
  48. }
  49. return true;
  50. }
  51. private static function env(string $name): string
  52. {
  53. $v = getenv($name);
  54. if (!is_string($v) || $v === '') {
  55. throw new RuntimeException("Required env var not set: {$name}");
  56. }
  57. return $v;
  58. }
  59. }