• #Basic oauth flow

    define('SSO_CLIENT_ID', '');
    define('SSO_CLIENT_SECRET', '');
    define('SSO_METADATA', 'https://PROVIDER.COM/.well-known/openid-configuration');
    define('SSO_REDIRECT_URI', URL_PUBLIC . 'sso/callback');
    
    public static function action_signin() {
      AuthUser::load();
      if (AuthUser::isLoggedIn()) {
        redirect('/admin');
        return;
      }
    
      $metadata = self::http(SSO_METADATA);
    
      $_SESSION['state'] = bin2hex(random_bytes(5));
      $_SESSION['code_verifier'] = bin2hex(random_bytes(50));
      $code_challenge = self::base64_urlencode(hash('sha256', $_SESSION['code_verifier'], true));
    
      $authorize_url = $metadata->authorization_endpoint.'?'.http_build_query([
        'response_type' => 'code',
        'client_id' => SSO_CLIENT_ID,
        'redirect_uri' => SSO_REDIRECT_URI,
        'state' => $_SESSION['state'],
        'scope' => 'openid email profile',
        'code_challenge' => $code_challenge,
        'code_challenge_method' => 'S256',
      ]);
    
      redirect($authorize_url);
    }
    
    public static function action_callback() {
      if(!isset($_SESSION['state']) || !isset($_GET['state']) || $_SESSION['state'] != $_GET['state']) {
        die('Authorization server returned an invalid state parameter');
      }
    
      if(isset($_GET['error'])) {
        die('Authorization server returned an error: '.htmlspecialchars($_GET['error']));
      }
    
      $metadata = self::http(SSO_METADATA);
    
      $response = self::http($metadata->token_endpoint, [
        'grant_type' => 'authorization_code',
        'code' => $_GET['code'],
        'redirect_uri' => SSO_REDIRECT_URI,
        'client_id' => SSO_CLIENT_ID,
        'client_secret' => SSO_CLIENT_SECRET,
        'code_verifier' => $_SESSION['code_verifier'],
      ]);
    
      if (isset($response->error)) {
        die('Authorization server returned an error: '.htmlspecialchars($response->error));
      }
    
      $userinfo = self::http($metadata->userinfo_endpoint, [
        'access_token' => $response->access_token,
      ]);
    
      if (!isset($userinfo->sub)) {
        die('Error fetching access token');
      }
    
      $login = self::createOrLogin($userinfo);
      if (!$login) {
        die('Authentication request was not successful');
      }
    
      redirect('/dashboard');
    }