Skip to main content

On Sale: GamesAssetsToolsTabletopComics
Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

OAuth Applications

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!

Introduction

The API documented in this page implements two flows of the OAuth 2.0 spec. If you're already familiar with them, you should only need to skim through the page and pick the implementation details you need.

  • The authorization code flow with PKCE is recommended for new integrations. It works with any standard OAuth 2.0 client library, and the access token never passes through the user’s browser.
  • The implicit flow is the original flow supported by itch.io. It is still supported for existing integrations.

In short, both flows work like this:

  • You redirect the user to /user/oauth
    • This is where you pass your client ID and the scope you need
  • The user sees a page where they can review the permissions (scopes) you're asking for.
  • If they accept, the user is redirected to the Authorization Callback URL you specified when registering the OAuth app. This is a page you control and you serve.
  • With the authorization code flow, the redirect includes a short-lived code in the query string, which you exchange for an access token with a POST request to api.itch.io.
  • With the implicit flow, the access token itself is included in the hash part of the URL.
    • The callback page you serve should include javascript code that extracts the access token you need and POSTs it securely to your server

There is also a QR code login for devices without a usable browser, available to approved clients.

Registering an OAuth application

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.

The authorization step

To let users choose to grant permissions to your apps, you should redirect them to the following address:

/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 settings
  • scope: 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: code for the authorization code flow, or token for the implicit flow.
  • state (optional): If this is specified, it will be included in the address the user is redirected to. See the Security Considerations section below.

The authorization code flow also requires:

  • code_challenge: The PKCE challenge, see Authorization code flow below.
  • code_challenge_method: Must be set to S256.

The parameters should be included as a query string. Here’s a sample authorization URL with dummy values for the authorization code flow:

/user/oauth?client_id=foobar&scope=profile:me&redirect_uri=https%3A%2F%2Fexample.org%2Fcallback&response_type=code&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&state=ZZZ

And for the implicit flow:

/user/oauth?client_id=foobar&scope=profile:me&redirect_uri=https%3A%2F%2Fexample.org%2F&response_type=token

Scopes

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.

Redirect URIs

The redirect URI (or Authorization callback address) is where a user will get redirected after they approve your request for credentials.

For example, if you specify the following redirect URL:

https://example.org/oauth/callback?a=b

Then with the authorization code flow, the user will get redirected to:

https://example.org/oauth/callback?a=b&code=XXX&state=ZZZ

And with the implicit flow, the access token is included in the hash part of the URL instead:

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 Implicit flow section for retrieval.

If the user declines, they are redirected back with error=access_denied and your state in place of the credentials, in the query string for the authorization code flow and in the hash for the implicit flow:

https://example.org/oauth/callback?a=b&error=access_denied&state=ZZZ

Loopback address (local http server)

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/callback.

For loopback addresses (127.0.0.1, [::1] or localhost) the port doesn’t have to match the one you registered. Your application can listen on any free port and pass the address it actually bound to as redirect_uri. The scheme (http), host and path must still match exactly, and the redirect_uri you send when exchanging the code must be identical to the one you sent in the authorization step.

Out-of-band authentication (copy/paste)

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 authorization code (or, in the implicit flow, the API key) and instructions to copy and paste it into your app.

This is especially useful in scenarios where:

  • You set the redirect URI to a loopback address
  • …but were not able to listen on that address
    • either because some other program was already listening on that port
    • or because the user did not allow your program to listen on a port (the Windows firewall will do that)

So, as a best practice, if you're implementing a desktop app, you should try to listen on a 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 code instead. With the authorization code flow the pasted value is useless to anyone who doesn’t also hold your code_verifier.

Custom URL schemes

A redirect URI with a custom scheme, like mygame://oauth/callback, is accepted. Be aware that custom schemes are not exclusive: any other application on the user’s machine can register the same scheme, and the operating system decides which one receives the redirect. Prefer a loopback address when you can, and if you do use a custom scheme, use the authorization code flow so an intercepted redirect doesn’t expose an access token.

This is the standard OAuth 2.0 authorization code grant with PKCE. Most OAuth 2.0 client libraries support it out of the box. Point the library at the following endpoints:

  • Authorization endpoint: /user/oauth
  • Token endpoint: https://api.itch.io/oauth/token

There is no client secret. PKCE is required for every client, including server-side web applications.

1. Create a PKCE verifier and challenge

Generate a random code_verifier (43 to 128 characters) and keep it in the session or 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))

Generate a new verifier for every login attempt. Only the challenge is sent in the authorization step. The verifier is sent at the end to prove the same client is finishing the login.

2. Redirect the user

Send the user to /user/oauth with response_type=code, the code_challenge and code_challenge_method=S256, along with the other parameters described in The authorization step.

3. Handle the redirect

After the user approves, they are redirected to your redirect_uri with code and state added to the query string:

https://example.org/oauth/callback?code=XXX&state=ZZZ

Check that state matches the value you sent. The code is single use and expires 10 minutes after it’s issued, so exchange it right away.

4. Exchange the code for an access token

POST https://api.itch.io/oauth/token

Send the parameters as a form (application/x-www-form-urlencoded). This request doesn’t take an Authorization header.

  • grant_type: authorization_code
  • code: the code from the redirect
  • code_verifier: the verifier from step 1
  • redirect_uri: the same redirect_uri you sent in the authorization step
  • client_id: your OAuth application’s client ID

Sample response:

{
  "access_token": "YOUR_ACCESS_TOKEN",
  "token_type": "bearer",
  "scope": "profile:me"
}

The response may include other fields. Only the ones listed above are part of the public API.

Use access_token in the Authorization header as described in Using the access token. The token doesn’t expire and there is no refresh token. If the user goes through the flow again, the same token is returned with its scopes widened to include any new ones you asked for.

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 {"error": "invalid_grant"}. A missing or malformed parameter responds with a 400 and {"error": "invalid_request", "error_description": "..."}. Start again from step 1.

If your application runs entirely in the browser, you can make the token request with fetch from the origin of your registered redirect URI. The response includes the Access-Control-Allow-Origin header for that origin.

Implicit flow

New integrations should use the authorization code flow 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.

Games and native applications

If your game is launched through the itch.io app, you don’t need OAuth at all: add the API scopes you need to your app manifest and the app provides an API key when it launches your game.

When your game or application runs on its own, use the authorization code flow:

  • Open the authorization URL in the user’s system browser. Don’t use an embedded web view: the user can’t check the address bar, won’t be logged in to itch.io there, and password managers and two-factor login work poorly.
  • Listen on a loopback address on any free port and pass it as redirect_uri. The code arrives in the query string, so a minimal HTTP handler is enough to read it. Fall back to copy/paste when you can’t listen.
  • Keep the code_verifier in memory until the exchange is done, and store the resulting access token the same way you'd store any other secret on the user’s machine.

For devices without a usable browser, see QR code login.

Using the access token

Once you've obtained an access token, either from the token endpoint or extracted from the hash part of the URL and posted to your server, 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.

Checking the access token’s permissions

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.

Revoking an access token

Access tokens don’t expire. To log a user out of your application, revoke the token:

POST https://api.itch.io/oauth/revoke

Send the parameters as a form (application/x-www-form-urlencoded). This request doesn’t take an Authorization header.

  • token: the access token to revoke
  • client_id: your OAuth application’s client ID

The server responds with a 200 and an empty JSON object whether or not the token existed, as described in RFC 7009. Only tokens issued to your application can be revoked this way. An unknown client_id responds with a 400 and {"error": "invalid_client"}.

Users can also revoke access to your application from their API keys settings at any time.

QR code login (device authorization grant)

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.

1. Create a PKCE verifier and challenge

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.

2. Start the login

POST https://api.itch.io/oauth/device

  • client_id: your OAuth application’s client ID
  • scope: 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 1
  • code_challenge_method: S256

Sample response:

{
  "device_code": "Gm0kTB4nW3tJqXfH9pZrV6LsYd2cA8eP",
  "user_code": "KX7T-4MPB",
  "verification_uri": "/user/oauth/device",
  "verification_uri_complete": "/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 expires
  • interval: seconds to wait between polls

An 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.

3. Show the QR code and wait

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.

4. Poll for the result

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 ID
  • device_code: the device_code from step 2

The 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 {"error": "invalid_grant"}.

5. Exchange the code for an API key

POST https://api.itch.io/oauth/token

  • grant_type: authorization_code
  • code: the code from the approved poll response
  • code_verifier: the verifier from step 1
  • redirect_uri: urn:itchio:poll
  • client_id: your OAuth application’s client ID
  • device_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"
}

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 {"error": "invalid_grant"}. Start again from step 1.

Security considerations

To avoid various types of attack, the OAuth 2.0 spec recommends only requesting the scopes you need:

  • Be specific: if all you need is profile:me, don’t request all of profile
  • If you need more permissions later, you can always make the user go through the flow again to expand the scope of your credentials.

Prefer the authorization code flow. With the implicit flow the access token appears in the browser’s address bar, so it ends up in browser history and is visible to any script or extension running on the callback page. With the authorization code flow only a short-lived, single-use code does, and it can’t be exchanged without the code_verifier that never left your application.

The 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

If you use the implicit flow, 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 (in the query string for the authorization code flow, as part of the hash for the implicit flow). You should check that the value you get back is equal to the one you passed in.