    async def _api_request(self, method, url, **kwargs):
        """Make an API request"""
        allow_403 = kwargs.pop('allow_403', False)
        headers = kwargs.setdefault('headers', {})
        headers.setdefault('Authorization', f'token {self.api_token}')
        # translate requests args to tornado's
        if self.certfile:
            kwargs["client_cert"] = self.certfile
        if self.keyfile:
            kwargs["client_key"] = self.keyfile
        if self.client_ca:
            kwargs["ca_certs"] = self.client_ca
        req = HTTPRequest(
            url,
            method=method,
            **kwargs,
        )
        try:
            r = await AsyncHTTPClient().fetch(req, raise_error=False)
        except Exception as e:
            app_log.error("Error connecting to %s: %s", self.api_url, e)
            msg = f"Failed to connect to Hub API at {self.api_url!r}."
            msg += f"  Is the Hub accessible at this URL (from host: {socket.gethostname()})?"
            if '127.0.0.1' in self.api_url:
                msg += (
                    "  Make sure to set c.JupyterHub.hub_ip to an IP accessible to"
                    + " single-user servers if the servers are not on the same host as the Hub."
                )
            raise HTTPError(500, msg)

        data = None
        try:
            status = HTTPStatus(r.code)
        except ValueError:
            app_log.error(
                f"Unknown error checking authorization with JupyterHub: {r.code}"
            )
            app_log.error(r.body.decode("utf8", "replace"))

        response_text = r.body.decode("utf8", "replace")
        if status.value == 403 and allow_403:
            pass
        elif status.value == 403:
            app_log.error(
                "I don't have permission to check authorization with JupyterHub, my auth token may have expired: [%i] %s",
                status.value,
                status.description,
            )
            app_log.error(response_text)
            raise HTTPError(
                500, "Permission failure checking authorization, I may need a new token"
            )
        elif status.value >= 500:
            app_log.error(
                "Upstream failure verifying auth token: [%i] %s",
                status.value,
                status.description,
            )
            app_log.error(response_text)
            raise HTTPError(502, "Failed to check authorization (upstream problem)")
        elif status.value >= 400:
            app_log.warning(
                "Failed to check authorization: [%i] %s",
                status.value,
                status.description,
            )
            app_log.warning(response_text)
            msg = "Failed to check authorization"
            # pass on error from oauth failure
            try:
                response = json.loads(response_text)
                # prefer more specific 'error_description', fallback to 'error'
                description = response.get(
                    "error_description", response.get("error", "Unknown error")
                )
            except Exception:
                pass
            else:
                msg += ": " + description
            raise HTTPError(500, msg)
        else:
            data = json.loads(response_text)

        return data
Make an API request
jupyterhub/services/auth.py