/** * Authenticates user via CS50 ID. If user is returning from CS50 ID, * returns associative array of user's claims, else redirects to CS50 ID * for authentication. * * @param string client_id * @param string client_secret * @param string scope * * @return array claims */ public static function authenticate($client_id, $client_secret, $scope = "openid profile") { // validate scope // https://tools.ietf.org/html/rfc6749#appendix-A.4 if (!preg_match("/^[\\x{21}\\x{23}-\\x{5B}\\x{5D}-\\x{7E}]([ \\x{21}\\x{23}-\\x{5B}\\x{5D}-\\x{7E}])*\$/", $scope)) { trigger_error("invalid scope", E_USER_ERROR); } // redirection URI try { // sans username and password (and fragment) $uri = \League\Uri\Schemes\Http::createFromServer($_SERVER)->withUserInfo(""); // sans code and state (which are reserved by OAuth2) $modifier = new \League\Uri\Modifiers\RemoveQueryKeys(["code", "state"]); $redirect_uri = $modifier->__invoke($uri)->__toString(); } catch (\Exception $e) { trigger_error("unable to infer redirect_uri", E_USER_ERROR); } // configure client $id = new ID($client_id, $client_secret, $redirect_uri, $scope); // if user is returning from CS50 ID, return claims if (isset($_GET["code"], $_GET["state"])) { return $id->getUser(); } // redirect to CS50 ID header("Location: " . $id->getLoginUrl()); exit; }