If you want to do some API requests on behalf of another user, you need to register an OAuth application.
For example, you might be creating a website that processes someone’s itch.io data in some way.
Or, you want to use the itch.io API in your game even when it’s launched without the itch.io app.
Tip: If you just want to use the itch.io API in your game, you can simply add the API scopes you need in your app manifest.
It’s by far the easiest for you to set up, and the best user experience for your players!
The API documented in this page implements the “Implicit flow” of the OAuth 2.0 spec. If you're already familiar with it, you should only need to skim through the page and pick the implementation details you need.
In short, the OAuth 2.0 implicit flows works like this:
https://itch.io/user/oauth
hash part of the URL.
As a developer, you can manage your OAuth applications from your user settings.
Try to keep things neat and tidy. If you have multiple websites or games using the itch.io API for a different purpose, create separate OAuth apps for them.
To let users choose to grant permissions to your apps, you should redirect them to the following address:
https://itch.io/user/oauth
It requires the following parameters:
client_id: The Client ID corresponding to your OAuth application, which you can retrieve from your OAuth application settingsscope: A space-separated list of scopes you'd like access to (see the Scopes section below)redirect_uri: The address of a page the user will be redirected to if
they accept to grant your app permissions. This must match your OAuth application settings. See the Redirect URI section below.response_type: Must be set to token for the implicit flow.state (optional): If this is specified, it will be included in the
hash part of the address the user is redirected to. See the Security Considerations section below.The parameters should be included as a query string. Here’s a sample authorization URL with dummy values:
https://itch.io/user/oauth?client_id=foobar&scope=profile:me&redirect_uri=https%3A%2F%2Fexample.org%2F&response_type=token
The following scopes are available for third-party OAuth applications:
Profile scopes:
profile:me – View the user’s public profile (username, avatar, etc.). Grants access to https://api.itch.io/profile.profile:games – List the games the user is developing. Grants access to https://api.itch.io/profile/games.profile:collections – List the user’s collections. Grants access to https://api.itch.io/profile/collections.profile:owned – List the games the user has purchased or claimed. Grants access to https://api.itch.io/profile/owned-keys.profile – Grants access to all profile:* scopes above.Game scopes:
game:view:ownership – Check if the user owns a specific game. Grants access to https://api.itch.io/games/:game_id/ownership. This endpoint only works for games owned by the OAuth application creator.game:view:rewards – List claimed rewards for games the user develops. Grants access to https://api.itch.io/games/:game_id/claimed-rewards.game:view:uploads – Download the files of games the user owns, games they develop, and free games. Grants access to https://api.itch.io/games/:game_id/uploads, https://api.itch.io/games/:game_id/download-sessions and https://api.itch.io/uploads/:upload_id/download.Collection scopes:
collection:edit – Create, edit, reorder and delete the user’s collections and the games in them. Grants access to the POST endpoints under https://api.itch.io/collections. Not included in profile or profile:collections.Scopes are hierarchical: requesting profile grants access to all profile:* endpoints. If you only need specific access, request the more specific scope (e.g., profile:me instead of profile).
See the server-side documentation for details on each endpoint.
The redirect URI (or Authorization callback address) is where a user will get redirected after they approve your request for credentials.
The credentials are included in the hash part of the URL.
For example, if you specify the following redirect URL:
https://example.org/oauth/callback?a=b
Then the user will get redirected to the following page:
https://example.org/oauth/callback?a=b#access_token=YYY&state=ZZZ
The hash part of the URL is encoded like a query string – see the next section for retrieval.
If you're creating a desktop application, you may have to set the redirect URI
to the loopback address, like http://127.0.0.1:34567.
If you set the redirect URI to urn:ietf:wg:oauth:2.0:oob, the user won’t be
redirected. Instead they'll be shown a page with the API key and instructions
to copy and paste it into your app.
This is especially useful in scenarios where:
So, as a best practice, if you're implementing a desktop app, you should
try to listen on your registered loopback address, and if you can’t, fall back
to urn:ietf:wg:oauth:2.0:oob and allow your user to copy & paste the API key instead.
The hash part of URLs is not seen by HTTP servers, or HTTP proxies. That’s why the OAuth 2.0 Implicit Flow puts sensitive information (the access token) in there.
That means you need to serve a page that includes a bit of JavaScript to retrieve the access token, and send it to your server, usually via an XHR).
It’s tempting to use a couple of regular expressions to retrieve the access token, but we encourage you to use libraries or standard APIs instead.
Here is example code to retrieve the access_token:
// this code assumes a recent browser or polyfill - see next paragraphs
// first, remove the '#' from the hash part of the URL
var queryString = window.location.hash.slice(1);
var params = new URLSearchParams(queryString);
var accessToken = params.get("access_token");
// you can also get the state param if you're using it:
var state = params.get("state");
See this code in action in this codepen
URLSearchParams is available in recent browsers, see the ‘Browser compatibility’ section of URLSearchParams’s MDN page.
If you need to support older browsers, you can use a polyfill: url-search-params comes with a build you can easily include in your website.
Once you've successfully extracted the access token from the hash part of the URL, posted it to your server with an XHR, and saved it in your database, you can use it to make API requests.
Access tokens given by the OAuth 2.0 flow are API keys. Use them with the
Authorization header when making requests to api.itch.io:
GET https://api.itch.io/profile
Authorization: Bearer YOUR_ACCESS_TOKEN
See the server-side API docs for the full list of available endpoints.
You can use https://api.itch.io/credentials/info to list the scopes associated
with an access token. See the server-side API docs for
details.
Handheld consoles and other devices without a usable browser can log a user in with a QR code instead. The device shows a QR code, the user scans it with their phone, approves the login on itch.io, and the device receives an API key. This follows the OAuth 2.0 device authorization grant with PKCE.
This flow is only available to approved clients. A regular OAuth application can’t use it. To request access, first register an OAuth application, then contact support with the subject OAuth application request: QR code login (device authorization grant). Include your OAuth application’s client ID, the device or platform you're building for, and what your app does.
Once your application is approved, change its redirect URI to
urn:itchio:poll in your OAuth application settings.
The device gets the result by polling, as described below, instead of
through a redirect.
The requests below are POST requests to api.itch.io, with the parameters
sent as a form (application/x-www-form-urlencoded). None of them take an
Authorization header.
Generate a random code_verifier (43 to 128 characters) and keep it on the
device. The code_challenge is the SHA-256 hash of the verifier, encoded as
base64url without padding:
code_challenge = base64url(sha256(code_verifier))
Only the challenge is sent when starting the login. The verifier is sent at the end to prove the same device is finishing it.
POST https://api.itch.io/oauth/device
client_id: your OAuth application’s client IDscope: a space-separated list of the scopes you need, from the
Scopes section above. For example, an
app that lists and downloads the user’s games would use
profile:me profile:owned game:view:uploads.code_challenge: the challenge from step 1code_challenge_method: S256Sample response:
{
"device_code": "Gm0kTB4nW3tJqXfH9pZrV6LsYd2cA8eP",
"user_code": "KX7T-4MPB",
"verification_uri": "https://itch.io/user/oauth/device",
"verification_uri_complete": "https://itch.io/user/oauth/device?code=tQ8wLk2VnR5xZp9bYc3fHs",
"expires_in": 600,
"interval": 5
}
device_code: used to poll for the result. Don’t show it to the user.user_code: a short code to show next to the QR code. The approval
page shows the same code so the user can check they're approving the
right device.verification_uri_complete: the address to encode in the QR code.
You can also show it as text for users who can’t scan the code.verification_uri: the approval page without the code. There is no
way to type a code on this page yet, so always send users to
verification_uri_complete.expires_in: seconds until the request expiresinterval: seconds to wait between pollsAn unknown or unapproved client_id, or an application whose redirect URI
isn’t urn:itchio:poll, returns a 404. A scope that isn’t in the Scopes list
returns a 400. Starting a login is rate limited: if you get an HTTP 429, wait
before trying again.
Show the QR code and user_code on the device. When the user opens the
address, itch.io asks them to log in if they aren’t already, then shows your
application’s name, the user_code, the permissions your scopes ask for, and
buttons to approve or deny.
While the QR code is showing, poll every interval seconds:
POST https://api.itch.io/oauth/device/poll
client_id: your OAuth application’s client IDdevice_code: the device_code from step 2The response has a status field:
pending: the user hasn’t decided yet. Poll again after interval
seconds.approved: the user approved the login. The response includes a
code to exchange in step 5.denied: the user denied the login. Stop polling.expired: the request expired, or its code was already exchanged.
Start again from step 1 with a new request and QR code.{
"status": "approved",
"code": "hWf3pQ9zL2mK7vXc4nB8tR6yJ1sD5gA0"
}
If you poll too often, the server responds with HTTP status 429. Wait longer before the next poll, for example by doubling the interval.
The poll request currently returns right away, but in the future it may wait
for the user to approve or deny before responding. Don’t use a short timeout
on this request, and wait interval seconds after each response comes back
rather than polling on a fixed timer.
An unknown device_code, or one that belongs to a different client_id,
returns a 400 with {"errors": ["invalid_grant"]}.
POST https://api.itch.io/oauth/token
grant_type: authorization_codecode: the code from the approved poll responsecode_verifier: the verifier from step 1redirect_uri: urn:itchio:pollclient_id: your OAuth application’s client IDdevice_info (optional): a short description of the device, eg.
Anbernic RG35XX H, MyApp 1.2.0. itch.io uses it to see which devices
and environments logins come from.Exchange the code right away. It can only be used once, and it expires 10 minutes after the user approves.
Sample response:
{
"access_token": "YOUR_ACCESS_TOKEN",
"token_type": "bearer",
"scope": "profile:me profile:owned game:view:uploads",
"key": {
"id": 1234,
"key": "YOUR_ACCESS_TOKEN",
"user_id": 29789,
"created_at": "2026-09-24 18:02:11"
}
}
Use access_token in the Authorization header as described in
Using the access token.
If the code is unknown, expired, already used, or the code_verifier,
redirect_uri or client_id don’t match, the server responds with a 400 and
{"errors": ["invalid_grant"]}. Start again from step 1.
To avoid various types of attack, the OAuth 2.0 spec recommends only requesting the scopes you need:
profile:me, don’t request all of profileThe OAuth Authorization callback page should be served over HTTPS to avoid man-in-the-middle attacks. Nowadays, getting an SSL certificate is easy thanks to efforts like Let’s Encrypt
The OAuth Authorization callback page should not include any third-party
javascript code (social sharing widgets, etc.) – if it does, you should at least
make sure your access token extraction code runs first and that it clears
window.location.hash.
A state parameter can be used as a nonce – it is generated by your server, included in the
login URL, and then again in the callback URL as part of the hash. You should check that the value
you get back is equal to the one you passed in.
Follow itch.io on YouTube, Bluesky, X, Facebook, or Join our Discord for new games and site updates.