Files
shields/tutorial-server-secrets.html
2025-03-02 11:21:43 +00:00

349 lines
25 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Tutorial: server-secrets</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Tutorial: server-secrets</h1>
<section>
<header>
<h2>server-secrets</h2>
</header>
<article>
<h1>Server Secrets</h1>
<p>It is possible to provide a token or credentials for a number of external
services. These may be used to lift a rate limit or provide access to
private resources from a self-hosted instance.</p>
<p>There are two ways of setting secrets:</p>
<ol>
<li>Via environment variables. This is a good way to set them in a PaaS
environment.</li>
</ol>
<pre class="prettyprint source lang-sh"><code>DRONE_TOKEN=...
DRONE_ORIGINS=&quot;https://drone.example.com&quot;
</code></pre>
<ol start="2">
<li>Via checked-in <code>config/local.yml</code>:</li>
</ol>
<pre class="prettyprint source lang-yml"><code>public:
services:
drone:
authorizedOrigins: ['https://drone.example.com']
private:
drone_token: '...'
</code></pre>
<p>For more complex scenarios, configuration files can cascade. See the <a href="https://github.com/lorenwest/node-config/wiki/Configuration-Files">node-config documentation</a>
for details.</p>
<h2>Authorized origins</h2>
<p>Several of the badges provided by Shields allow users to specify the target
URL/server of the upstream instance to use via a query parameter in the badge URL
(e.g. https://img.shields.io/nexus/s/com.google.guava/guava?server=https%3A%2F%2Foss.sonatype.org).
This supports scenarios where your users may need badges from multiple upstream
targets, for example if you have more than one Nexus server.</p>
<p>Accordingly, if you configure credentials for one of these services with your
self-hosted Shields instance, you must also specifically authorize the hosts
to which the credentials are allowed to be sent. If your self-hosted Shields
instance then receives a badge request for a target that does not match any
of the authorized origins, one of two things will happen:</p>
<ul>
<li>if credentials are required for the targeted service, Shields will render
an error badge.</li>
<li>if credentials are optional for the targeted service, Shields will attempt
the request, but without sending any credentials.</li>
</ul>
<p>When setting authorized origins through an environment variable, use a space
to separate multiple origins. Note that failing to define authorized origins
for a service will default to an empty list, i.e. no authorized origins.</p>
<p>It is highly recommended to use <code>https</code> origins with valid SSL, to avoid the
possibility of exposing your credentials, for example through DNS-based attacks.</p>
<p>It is also recommended to use tokens for a service account having
<a href="https://en.wikipedia.org/wiki/Principle_of_least_privilege">the fewest privileges needed</a> for fetching the relevant status
information.</p>
<h2>Services</h2>
<h3>Azure DevOps</h3>
<ul>
<li><code>AZURE_DEVOPS_TOKEN</code> (yml: <code>private.azure_devops_token</code>)</li>
</ul>
<p>An Azure DevOps Token (PAT) is required for accessing <a href="https://docs.microsoft.com/en-us/azure/devops/organizations/public/about-public-projects?view=vsts">private Azure DevOps projects</a>.</p>
<p><a href="https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=vsts#create-personal-access-tokens-to-authenticate-access">Create a PAT</a> using an account that has access to your target Azure DevOps projects. Your PAT only needs the following <a href="https://docs.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/oauth?view=vsts#scopes">scopes:</a></p>
<ul>
<li><code>Build (read)</code></li>
<li><code>Release (read)</code></li>
<li><code>Test Management (read)</code></li>
</ul>
<h3>Bitbucket (Cloud)</h3>
<ul>
<li><code>BITBUCKET_USER</code> (yml: <code>private.bitbucket_username</code>)</li>
<li><code>BITBUCKET_PASS</code> (yml: <code>private.bitbucket_password</code>)</li>
</ul>
<p>Bitbucket badges use basic auth. Provide a username and password to give your
self-hosted Shields installation access to private repositories hosted on bitbucket.org.</p>
<h3>Bitbucket Server</h3>
<ul>
<li><code>BITBUCKET_SERVER_ORIGINS</code> (yml: <code>public.services.bitbucketServer.authorizedOrigins</code>)</li>
<li><code>BITBUCKET_SERVER_USER</code> (yml: <code>private.bitbucket_server_username</code>)</li>
<li><code>BITBUCKET_SERVER_PASS</code> (yml: <code>private.bitbucket_server_password</code>)</li>
</ul>
<p>Bitbucket badges use basic auth. Provide a username and password to give your
self-hosted Shields installation access to a private Bitbucket Server instance.</p>
<h3>CurseForge</h3>
<ul>
<li><code>CURSEFORGE_API_KEY</code> (yml: <code>private.curseforge_api_key</code>)</li>
</ul>
<p>A CurseForge API key is required to use the <a href="https://docs.curseforge.com">CurseForge API</a>. To obtain
an API key, <a href="https://console.curseforge.com/#/signup">signup to CurseForge Console</a> with a Google account and
create an organization, then go to the <a href="https://console.curseforge.com/#/api-keys">API keys page</a> and copy the
generated API key.</p>
<h3>Discord</h3>
<p>Using a token for Discord is optional but will allow higher API rates.</p>
<ul>
<li><code>DISCORD_BOT_TOKEN</code> (yml: <code>private.discord_bot_token</code>)</li>
</ul>
<p>Register an application in the <a href="https://discord.com/developers">Discord developer console</a>.
To obtain a token, simply create a bot for your application.</p>
<h3>DockerHub</h3>
<p>Using authentication for DockerHub is optional but can be used to allow
higher API rates or access to private repos.</p>
<ul>
<li><code>DOCKERHUB_USER</code> (yml: <code>private.dockerhub_username</code>)</li>
<li><code>DOCKERHUB_PAT</code> (yml: <code>private.dockerhub_pat</code>)</li>
</ul>
<p><code>DOCKERHUB_PAT</code> is a Personal Access Token. Generate a token in your
<a href="https://hub.docker.com/settings/security">account security settings</a> with
&quot;Read-Only&quot; or &quot;Public Repo Read-Only&quot;, depending on your needs.</p>
<h3>Drone</h3>
<ul>
<li><code>DRONE_ORIGINS</code> (yml: <code>public.services.drone.authorizedOrigins</code>)</li>
<li><code>DRONE_TOKEN</code> (yml: <code>private.drone_token</code>)</li>
</ul>
<p>The self-hosted Drone API <a href="https://0-8-0.docs.drone.io/api-authentication/">requires authentication</a>. Log in to your
Drone instance and obtain a token from the user profile page.</p>
<h3>GitHub</h3>
<ul>
<li><code>GITHUB_URL</code> (yml: <code>public.services.github.baseUri</code>)</li>
<li><code>GH_TOKEN</code> (yml: <code>private.gh_token</code>)</li>
</ul>
<p>Because of GitHub rate limits, you will need to provide a token, or else badges
will stop working once you hit 60 requests per hour, the
<a href="https://developer.github.com/v3/#rate-limiting">unauthenticated rate limit</a>.</p>
<p>You can <a href="https://github.com/settings/tokens">create a personal access token</a> (PATs) through the
GitHub website. When you create the token, you can choose to give read access
to your repositories. If you do that, your self-hosted Shields installation
will have access to your private repositories.</p>
<p>For most users we recommend using a classic PAT as opposed to a <a href="https://github.blog/2022-10-18-introducing-fine-grained-personal-access-tokens-for-github/">fine-grained PAT</a>.
It is possible to request a fairly large subset of the GitHub badge suite using a
fine-grained PAT for authentication but there are also some badges that won't work.
This is because some of our badges make use of GitHub's v4 GraphQL API and the
GraphQL API only supports authentication with a classic PAT.</p>
<p>When a <code>gh_token</code> is specified, it is used in place of the Shields token
rotation logic.</p>
<p><code>GITHUB_URL</code> can be used to optionally send all the GitHub requests to a
GitHub Enterprise server. This can be done in conjunction with setting a
token, though it's not required.</p>
<ul>
<li><code>GH_CLIENT_ID</code> (yml: <code>private.gh_client_id</code>)</li>
<li><code>GH_CLIENT_SECRET</code> (yml: <code>private.gh_client_secret</code>)</li>
</ul>
<p>These settings are used by shields.io for GitHub OAuth app authorization
but will not be necessary for most self-hosted installations. See
<a href="./production-hosting.md">production-hosting.md</a>.</p>
<h3>Gitea</h3>
<ul>
<li><code>GITEA_ORIGINS</code> (yml: <code>public.services.gitea.authorizedOrigins</code>)</li>
<li><code>GITEA_TOKEN</code> (yml: <code>private.gitea_token</code>)</li>
</ul>
<p>A Gitea <a href="https://docs.gitea.com/development/api-usage#generating-and-listing-api-tokens">Personal Access Token</a> is required for accessing private content. If you need a Gitea token for your self-hosted Shields server then we recommend limiting the scopes to the minimal set necessary for the badges you are using.</p>
<h3>GitLab</h3>
<ul>
<li><code>GITLAB_ORIGINS</code> (yml: <code>public.services.gitlab.authorizedOrigins</code>)</li>
<li><code>GITLAB_TOKEN</code> (yml: <code>private.gitlab_token</code>)</li>
</ul>
<p>A GitLab <a href="https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html">Personal Access Token</a> is required for accessing private content. If you need a GitLab token for your self-hosted Shields server then we recommend limiting the scopes to the minimal set necessary for the badges you are using.</p>
<h3>Jenkins CI</h3>
<ul>
<li><code>JENKINS_ORIGINS</code> (yml: <code>public.services.jenkins.authorizedOrigins</code>)</li>
<li><code>JENKINS_USER</code> (yml: <code>private.jenkins_user</code>)</li>
<li><code>JENKINS_PASS</code> (yml: <code>private.jenkins_pass</code>)</li>
</ul>
<p>Provide a username and password to give your self-hosted Shields installation
access to a private Jenkins CI instance.</p>
<h3>Jira</h3>
<ul>
<li><code>JIRA_ORIGINS</code> (yml: <code>public.services.jira.authorizedOrigins</code>)</li>
<li><code>JIRA_USER</code> (yml: <code>private.jira_user</code>)</li>
<li><code>JIRA_PASS</code> (yml: <code>private.jira_pass</code>)</li>
</ul>
<p>Provide a username and password to give your self-hosted Shields installation
access to a private JIRA instance.</p>
<h3>Libraries.io/Bower</h3>
<ul>
<li><code>LIBRARIESIO_TOKENS</code> (yml: <code>private.librariesio_tokens</code>)</li>
</ul>
<p>Note that the Bower badges utilize the Libraries.io API, so use this secret for both Libraries.io badges and/or Bower badges.</p>
<p>Just like the <code>*_ORIGINS</code> type secrets, this value can accept a single token as a string, or a group of tokens provided as an array of strings. For example:</p>
<pre class="prettyprint source lang-yaml"><code>private:
librariesio_tokens: my-token
## Or
private:
librariesio_tokens: [my-token some-other-token]
</code></pre>
<p>When using the environment variable with multiple tokens, be sure to use a space to separate the tokens, e.g. <code>LIBRARIESIO_TOKENS=&quot;my-token some-other-token&quot;</code></p>
<h3>Nexus</h3>
<ul>
<li><code>NEXUS_ORIGINS</code> (yml: <code>public.services.nexus.authorizedOrigins</code>)</li>
<li><code>NEXUS_USER</code> (yml: <code>private.nexus_user</code>)</li>
<li><code>NEXUS_PASS</code> (yml: <code>private.nexus_pass</code>)</li>
</ul>
<p>Provide a username and password to give your self-hosted Shields installation
access to your private nexus repositories.</p>
<h3>npm</h3>
<ul>
<li><code>NPM_ORIGINS</code> (yml: <code>public.services.npm.authorizedOrigins</code>)</li>
<li><code>NPM_TOKEN</code> (yml: <code>private.npm_token</code>)</li>
</ul>
<p><a href="https://docs.npmjs.com/getting-started/working_with_tokens">Generate an npm token</a> to give your self-hosted Shields
installation access to private npm packages</p>
<h3>Open Build Service</h3>
<ul>
<li><code>OBS_USER</code> (yml: <code>private.obs_user</code>)</li>
<li><code>OBS_PASS</code> (yml: <code>private.obs_user</code>)</li>
</ul>
<p>Only authenticated users are allowed to access the Open Build Service API.
Authentication is done by sending a Basic HTTP Authorisation header. A user
account for the <a href="https://build.opensuse.org">reference instance</a> is a SUSE
IdP account, which can be created <a href="https://idp-portal.suse.com/univention/self-service/#page=createaccount">here</a>.</p>
<p>While OBS supports <a href="https://openbuildservice.org/help/manuals/obs-user-guide/cha.obs.authorization.token.html#id-1.5.10.16.4">API tokens</a>,
they can only be scoped to execute specific actions on a POST request. This
means however, that an actual account is required to read the build status
of a package.</p>
<h3>OpenCollective</h3>
<ul>
<li><code>OPENCOLLECTIVE_TOKEN</code> (yml: <code>private.opencollective_token</code>)</li>
</ul>
<p>OpenCollective's GraphQL API only allows 10 reqs/minute for anonymous users.
An <a href="https://graphql-docs-v2.opencollective.com/access">API token</a>
can be provided to access a higher rate limit of 100 reqs/minute.</p>
<h3>Pepy</h3>
<ul>
<li><code>PEPY_KEY</code> (yml: <code>private.pepy_key</code>)</li>
</ul>
<p>The Pepy API requires authentication. To obtain a key,
Create an account, sign in and obtain generate a key on your
<a href="https://www.pepy.tech/user">account page</a>.</p>
<h3>PyPI</h3>
<ul>
<li><code>PYPI_URL</code> (yml: <code>public.pypi.baseUri</code>)</li>
</ul>
<p><code>PYPI_URL</code> can be used to optionally send all the PyPI requests to a Self-hosted Pypi registry,
users can also override this by query parameter <code>pypiBaseUrl</code>.</p>
<h3>Reddit</h3>
<p>Using a token for Reddit is optional but will allow higher API rates.</p>
<ul>
<li><code>REDDIT_CLIENT_ID</code> (yml: <code>private.reddit_client_id</code>)</li>
<li><code>REDDIT_CLIENT_SECRET</code> (yml: <code>private.reddit_client_secret</code>)</li>
</ul>
<p>Register to use the API using <a href="https://support.reddithelp.com/hc/en-us/requests/new?ticket_form_id=14868593862164">this form</a>
and create an app in the <a href="https://www.reddit.com/prefs/apps">Reddit preferences page</a>
in order to obtain a client id and a client secret for making Reddit API calls.</p>
<h3>SymfonyInsight (formerly Sensiolabs)</h3>
<ul>
<li><code>SL_INSIGHT_USER_UUID</code> (yml: <code>private.sl_insight_userUuid</code>)</li>
<li><code>SL_INSIGHT_API_TOKEN</code> (yml: <code>private.sl_insight_apiToken</code>)</li>
</ul>
<p>The SymfonyInsight API requires authentication. To obtain a token,
Create an account, sign in and obtain a uuid and token from your
<a href="https://insight.sensiolabs.com/account">account page</a>.</p>
<h3>SonarQube</h3>
<ul>
<li><code>SONAR_ORIGINS</code> (yml: <code>public.services.sonar.authorizedOrigins</code>)</li>
<li><code>SONARQUBE_TOKEN</code> (yml: <code>private.sonarqube_token</code>)</li>
</ul>
<p><a href="https://docs.sonarqube.org/latest/user-guide/user-token/">Generate a token</a>
to give your self-hosted Shields installation access to a
private SonarQube instance or private project on a public instance.</p>
<h3>StackApps (for StackExchange and StackOverflow)</h3>
<ul>
<li><code>STACKAPPS_API_KEY</code>: (yml: <code>private.stackapps_api_key</code>)</li>
</ul>
<p>Anonymous requests to the stackexchange API are limited to 300 calls per day.
To increase your quota to 10,000 calls per day, create an account at
<a href="https://stackapps.com/">StackApps</a> and
<a href="https://stackapps.com/apps/oauth/register">register an OAuth app</a>. Having registered
an OAuth app, you'll be granted a key which can be used to increase your request quota.
It is not necessary to performa full OAuth Flow to gain an access token.</p>
<h3>TeamCity</h3>
<ul>
<li><code>TEAMCITY_ORIGINS</code> (yml: <code>public.services.teamcity.authorizedOrigins</code>)</li>
<li><code>TEAMCITY_USER</code> (yml: <code>private.teamcity_user</code>)</li>
<li><code>TEAMCITY_PASS</code> (yml: <code>private.teamcity_pass</code>)</li>
</ul>
<p>Provide a username and password to give your self-hosted Shields installation
access to your private nexus repositories.</p>
<h3>Twitch</h3>
<ul>
<li><code>TWITCH_CLIENT_ID</code> (yml: <code>private.twitch_client_id</code>)</li>
<li><code>TWITCH_CLIENT_SECRET</code> (yml: <code>private.twitch_client_secret</code>)</li>
</ul>
<p>Register an application in the <a href="https://dev.twitch.tv/console">Twitch developer console</a>
in order to obtain a client id and a client secret for making Twitch API calls.</p>
<h3>Weblate</h3>
<ul>
<li><code>WEBLATE_ORIGINS</code> (yml: <code>public.services.weblate.authorizedOrigins</code>)</li>
<li><code>WEBLATE_API_KEY</code> (yml: <code>private.weblate_api_key</code>)</li>
</ul>
<p>By default Weblate throttles <a href="https://docs.weblate.org/en/latest/api.html#authentication-and-generic-parameters">unauthenticated request</a>
to only 100 requests per day, after this you will need an API key or else
badges will stop working.</p>
<p>You can find your Weblate API key in your profile under
<a href="https://hosted.weblate.org/accounts/profile/#api">&quot;API access&quot;</a>.</p>
<h3>YouTube</h3>
<ul>
<li><code>YOUTUBE_API_KEY</code> (yml: <code>private.youtube_api_key</code>)</li>
</ul>
<p>The YouTube API requires authentication. To obtain an API key,
log in to a Google account, go to the <a href="https://console.developers.google.com/apis/credentials">credentials page</a>,
and create an API key for the YouTube Data API v3.</p>
<h2>Error reporting</h2>
<ul>
<li><code>SENTRY_DSN</code> (yml: <code>private.sentry_dsn</code>)</li>
</ul>
<p>A <a href="https://docs.sentry.io/error-reporting/quickstart/?platform=javascript#configure-the-dsn">Sentry DSN</a> may be used to send error reports from your installation to
<a href="http://sentry.io/">Sentry.io</a>. For more info, see the <a href="https://github.com/badges/shields/blob/master/doc/self-hosting.md#sentry">self hosting docs</a>.</p>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-badge-maker.html">badge-maker</a></li><li><a href="module-badge-maker_lib_xml.html">badge-maker/lib/xml</a></li><li><a href="module-core_base-service_base.html">core/base-service/base</a></li><li><a href="module-core_base-service_base-graphql.html">core/base-service/base-graphql</a></li><li><a href="module-core_base-service_base-json.html">core/base-service/base-json</a></li><li><a href="module-core_base-service_base-svg-scraping.html">core/base-service/base-svg-scraping</a></li><li><a href="module-core_base-service_base-toml.html">core/base-service/base-toml</a></li><li><a href="module-core_base-service_base-xml.html">core/base-service/base-xml</a></li><li><a href="module-core_base-service_base-yaml.html">core/base-service/base-yaml</a></li><li><a href="module-core_base-service_errors.html">core/base-service/errors</a></li><li><a href="module-core_base-service_graphql.html">core/base-service/graphql</a></li><li><a href="module-core_base-service_openapi.html">core/base-service/openapi</a></li><li><a href="module-core_base-service_resource-cache.html">core/base-service/resource-cache</a></li><li><a href="module-core_base-service_service-definitions.html">core/base-service/service-definitions</a></li><li><a href="module-core_server_server.html">core/server/server</a></li><li><a href="module-core_service-test-runner_create-service-tester.html">core/service-test-runner/create-service-tester</a></li><li><a href="module-core_service-test-runner_icedfrisby-shields.html">core/service-test-runner/icedfrisby-shields</a></li><li><a href="module-core_service-test-runner_runner.html">core/service-test-runner/runner</a></li><li><a href="module-core_service-test-runner_service-tester.html">core/service-test-runner/service-tester</a></li><li><a href="module-core_service-test-runner_services-for-title.html">core/service-test-runner/services-for-title</a></li><li><a href="module-core_token-pooling_token-pool.html">core/token-pooling/token-pool</a></li><li><a href="module-services_build-status.html">services/build-status</a></li><li><a href="module-services_color-formatters.html">services/color-formatters</a></li><li><a href="module-services_contributor-count.html">services/contributor-count</a></li><li><a href="module-services_date.html">services/date</a></li><li><a href="module-services_downloads.html">services/downloads</a></li><li><a href="module-services_dynamic-common.html">services/dynamic-common</a></li><li><a href="module-services_dynamic_json-path.html">services/dynamic/json-path</a></li><li><a href="module-services_endpoint-common.html">services/endpoint-common</a></li><li><a href="module-services_licenses.html">services/licenses</a></li><li><a href="module-services_package-json-helpers.html">services/package-json-helpers</a></li><li><a href="module-services_php-version.html">services/php-version</a></li><li><a href="module-services_pipenv-helpers.html">services/pipenv-helpers</a></li><li><a href="module-services_route-builder.html">services/route-builder</a></li><li><a href="module-services_size.html">services/size</a></li><li><a href="module-services_steam_steam-base.html">services/steam/steam-base</a></li><li><a href="module-services_text-formatters.html">services/text-formatters</a></li><li><a href="module-services_validators.html">services/validators</a></li><li><a href="module-services_version.html">services/version</a></li><li><a href="module-services_website-status.html">services/website-status</a></li><li><a href="module-services_winget_version.html">services/winget/version</a></li></ul><h3>Classes</h3><ul><li><a href="BaseThunderstoreService.html">BaseThunderstoreService</a></li><li><a href="module-badge-maker_lib_xml-ElementList.html">ElementList</a></li><li><a href="module-badge-maker_lib_xml-XmlElement.html">XmlElement</a></li><li><a href="module-core_base-service_base-graphql-BaseGraphqlService.html">BaseGraphqlService</a></li><li><a href="module-core_base-service_base-json-BaseJsonService.html">BaseJsonService</a></li><li><a href="module-core_base-service_base-svg-scraping-BaseSvgScrapingService.html">BaseSvgScrapingService</a></li><li><a href="module-core_base-service_base-toml-BaseTomlService.html">BaseTomlService</a></li><li><a href="module-core_base-service_base-xml-BaseXmlService.html">BaseXmlService</a></li><li><a href="module-core_base-service_base-yaml-BaseYamlService.html">BaseYamlService</a></li><li><a href="module-core_base-service_base-BaseService.html">BaseService</a></li><li><a href="module-core_base-service_errors-Deprecated.html">Deprecated</a></li><li><a href="module-core_base-service_errors-ImproperlyConfigured.html">ImproperlyConfigured</a></li><li><a href="module-core_base-service_errors-Inaccessible.html">Inaccessible</a></li><li><a href="module-core_base-service_errors-InvalidParameter.html">InvalidParameter</a></li><li><a href="module-core_base-service_errors-InvalidResponse.html">InvalidResponse</a></li><li><a href="module-core_base-service_errors-NotFound.html">NotFound</a></li><li><a href="module-core_base-service_errors-ShieldsRuntimeError.html">ShieldsRuntimeError</a></li><li><a href="module-core_server_server-Server.html">Server</a></li><li><a href="module-core_service-test-runner_runner-Runner.html">Runner</a></li><li><a href="module-core_service-test-runner_service-tester-ServiceTester.html">ServiceTester</a></li><li><a href="module-core_token-pooling_token-pool-Token.html">Token</a></li><li><a href="module-core_token-pooling_token-pool-TokenPool.html">TokenPool</a></li><li><a href="module-services_route-builder.html">services/route-builder</a></li><li><a href="module-services_steam_steam-base-BaseSteamAPI.html">BaseSteamAPI</a></li></ul><h3>Tutorials</h3><ul><li><a href="tutorial-TUTORIAL.html">TUTORIAL</a></li><li><a href="tutorial-adding-new-config-values.html">adding-new-config-values</a></li><li><a href="tutorial-authentication.html">authentication</a></li><li><a href="tutorial-badge-urls.html">badge-urls</a></li><li><a href="tutorial-code-walkthrough.html">code-walkthrough</a></li><li><a href="tutorial-deprecating-badges.html">deprecating-badges</a></li><li><a href="tutorial-input-validation.html">input-validation</a></li><li><a href="tutorial-json-format.html">json-format</a></li><li><a href="tutorial-performance-testing.html">performance-testing</a></li><li><a href="tutorial-production-hosting.html">production-hosting</a></li><li><a href="tutorial-releases.html">releases</a></li><li><a href="tutorial-self-hosting.html">self-hosting</a></li><li><a href="tutorial-server-secrets.html">server-secrets</a></li><li><a href="tutorial-service-tests.html">service-tests</a></li><li><a href="tutorial-static-badges.html">static-badges</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createNumRequestCounter">createNumRequestCounter</a></li><li><a href="global.html#fakeJwtToken">fakeJwtToken</a></li><li><a href="global.html#generateFakeConfig">generateFakeConfig</a></li><li><a href="global.html#getBadgeExampleCall">getBadgeExampleCall</a></li><li><a href="global.html#getServiceClassAuthOrigin">getServiceClassAuthOrigin</a></li><li><a href="global.html#isMetricWithPattern">isMetricWithPattern</a></li><li><a href="global.html#testAuth">testAuth</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sun Mar 02 2025 11:21:42 GMT+0000 (Coordinated Universal Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>