public static function authenticate() {
    // If a client does't support cookies, they can use the X-TILMELDAUTH header
    // to provide the auth token.
    if (!empty($_SERVER['HTTP_X_TILMELDAUTH']) && empty($_COOKIE['TILMELDAUTH'])) {
      $fromAuthHeader = true;
      $authToken = $_SERVER['HTTP_X_TILMELDAUTH'];
    } elseif (!empty($_COOKIE['TILMELDAUTH'])) {
      $fromAuthHeader = false;
      $authToken = $_COOKIE['TILMELDAUTH'];
    } else {
      return false;
    }
    $setupUrlParts = parse_url(self::$config['setup_url']);
    $setupHost = $setupUrlParts['host'].
      (array_key_exists('port', $setupUrlParts) ? ':'.$setupUrlParts['port'] : '');
    if ($_SERVER['HTTP_HOST'] === $setupHost
        && $_SERVER['REQUEST_URI'] === $setupUrlParts['path']
      ) {
      // The request is for the setup app, so don't check for the XSRF token.
      $extract = self::$config['jwt_extract']($authToken);
    } else {
      // The request is for something else, so check for a valid XSRF token.
      if (empty($_SERVER['HTTP_X_XSRF_TOKEN'])) {
        return false;
      }

      $extract = self::$config['jwt_extract'](
          $authToken,
          $_SERVER['HTTP_X_XSRF_TOKEN']
      );
    }

    if (!$extract) {
      self::logout();
      return false;
    }
    $guid = $extract['guid'];
    $expire = $extract['expire'];

    $user = Nymph::getEntity(
        ['class' => '\Tilmeld\Entities\User'],
        ['&',
          'guid' => $guid
        ]
    );
    if (!$user || !$user->guid || !$user->enabled) {
      self::logout();
      return false;
    }

    if ($expire < time() + self::$config['jwt_renew']) {
      // If the user is less than renew time from needing a new token, give them
      // a new one.
      self::login($user, $fromAuthHeader);
    } else {
      self::fillSession($user);
    }
    return true;
  }