Authorization
Almost all of Path of Exile's developer APIs require authorization of an existing Path of Exile account to use. This helps us enforce fair rate-limits as well as having a point of contact if anything goes wrong.
For this purpose we use an implementation of the OAuth 2.0 framework. This document will describe how to generate access tokens for users using your application's credentials.
OAuth 2.0
OAuth 2.0 is a popular and common way for an application to act in limited ways on behalf of a user.
There are many resources online documenting the basic idea as well as frameworks that can help you understand how the process works.
For this reason our implementation closely follows the original specification as well as taking guidance from some key extensions.
- The OAuth 2.0 Authorization Framework (RFC 6749)
- The OAuth 2.0 Authorization Framework: Bearer Token Usage (RFC 6750)
- Proof Key for Code Exchange by OAuth Public Clients (RFC 7636)
- OAuth 2.0 Threat Model and Security Considerations (RFC 6819)
- OAuth 2.0 Token Revocation (RFC 7009)
- OAuth 2.0 Token Introspection (RFC 7662)
- OAuth 2.0 for Native Apps (RFC 8252)
Users can review and revoke their tokens on their profile's applications page at any time.
OAuth Server Endpoints
-
/oauth/authorize
- Authorization page for obtaining user consent.
-
/oauth/token
- Endpoint for creating tokens.
-
/oauth/token/revoke (requires the oauth:revoke scope)
- Endpoint for revoking tokens.
-
/oauth/token/introspect (requires the oauth:introspect scope)
- Endpoint for checking tokens.
Errors
Unlike our other APIs, the endpoints above will return error messages according to the relevant RFC.
Client Types
OAuth 2.0 defines two client types which we support in different ways. The vast majority of applications should use a Confidential Client.
Confidential Clients
A confidential client is backend by a secure server controlled by the application owner. These clients:
- May use any of the available grant types. Any redirect URIs must point to a domain controlled by the application owner.
- Have access tokens that last for 28 days and refresh tokens that last for 90 days.
- Usually have individual rate-limits per client.
Public Clients
A public client is one without a method of securely storing any credentials. The most common example of this is an application that runs on the user's desktop. These clients:
- Must only use the Authorization Code (with PKCE) grant type and must use a local redirect URI.
- Cannot use any
service:*
scopes.
- Have access tokens that last for 10 hours and refresh tokens that last for 7 days.
- Have shared rate-limits between all other public clients.
- Display a warning message to the end user when authorizing; stating that the authenticity of the request is unverifiable.
Available Scopes
Accounts
-
account:profile
— for access to the account's basic profile information.
-
account:leagues
— for viewing the account's available leagues (including private leagues).
-
account:stashes
— for viewing the account's stashes and items.
-
account:characters
— for viewing the account's characters and inventories.
-
account:league_accounts
— for viewing the account's allocated atlas passives.
-
account:item_filter
— for managing the account's item filters.
Services
Requires a confidential client with the client_credentials
grant type.
-
service:leagues
— for fetching leagues.
-
service:leagues:ladder
— for fetching league ladders.
-
service:pvp_matches
— for fetching PvP matches.
-
service:pvp_matches:ladder
— for fetching PvP match ladders.
-
service:psapi
— for access to the Public Stash API.
Grant Types
Authorization Code Grant (with Proof Key of Code Exchange, or PKCE)
This grant is used when your application needs access to act on another user's behalf. All authentication is done by the Path of Exile's OAuth server and no user credentials are ever shared or exchanged.
The most important step is sending the user to the authorization page which presents them with the details of your request.
Flow:
-
Start by performing the initial PKCE steps:
-
// PHP example
$base64url_encode = fn(string $value): string => \rtrim(\strtr(\base64_encode($value), '+/', '-_'), '=');
$secret = \random_bytes(32);
$code_verifier = $base64url_encode($secret);
$code_challenge = $base64url_encode(\hash('sha256', $code_verifier, true));
-
- Generate a
code_verifier
as described in RFC 7636 Section 4.1. There should be sufficient entropy (at least 32-bytes) used to ensure the resulting value cannot be guessed.
- From this, create a
code_challenge
by base64url-encoding the SHA256 hash of the code_verifier
.
-
Generate an authorization URL and allow the user to navigate to it:
-
https://www.pathofexile.com/oauth/authorize
?client_id=example
&response_type=code
&scope=account:profile
&state=10ceb8104963e91e47a95f4138448ecf
&redirect_uri=https://example.com
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
client_id
is your registered application's client id.
response_type
is always code
.
scope
is a space-separated list of requested scopes.
state
is a code or hash that you generate to track the request.
redirect_uri
is the URL that you want the result of the authorization request to be sent to. This must match your client's registered URI.
code_challenge
is the code_challenge
you generated in the first step.
code_challenge_method
must be S256
.
-
On success the user will be redirected to your
redirect_uri
with a code
and the state
as query parameters.
-
On failure the user will also be redirected to your
redirect_uri
with details according to Section 4.1.2.1.
-
Check that the
state
parameter matches one that you have generated. This helps ensure that the request comes from the correct instance of your application.
-
Exchange the code for an access token using your application's credentials.
-
Send a
POST
request to /oauth/token like in the following example:
POST https://www.pathofexile.com/oauth/token
...
Content-Type: application/x-www-form-urlencoded
client_id=example
&client_secret=verysecret
&grant_type=authorization_code
&code=d25cc653854f1d4db9c0797a30a374c6
&redirect_uri=https://example.com
&scope=account:profile
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
client_id
is your registered application's client id.
client_secret
is your registered application's client secret, if it has one.
grant_type
is always authorization_code
.
code
is the authorization code obtained previously.
scope
is a space-separated list of requested scopes.
redirect_uri
is the URL that you received the authorization code with.
code_verifier
is the code_verifier
you generated in the first step.
- Authorization codes only last for 30 seconds, so make sure to exchange them quickly!
-
On success you will receive a response with an access and refresh token for the user:
{
"access_token": "486132c90fedb152360bc0e1aa54eea155768eb9",
"expires_in": 2592000,
"token_type": "bearer",
"scope": "account:profile",
"username": "Novynn",
"sub": "c5b9c286-8d05-47af-be41-67ab10a8c53e",
"refresh_token": "17abaa74e599192f7650a4b89b6e9dfef2ff68cd"
}
Client Credentials Grant
This grant can be used by an application in order to access services unrelated to an individual account that are exposed as part of the Path of Exile API.
Unlike other tokens these ones do not have a set expiration time. They can still be revoked manually via your application settings page.
Flow:
-
Submit a request for a token using the
client_credentials
grant:
-
Send a
POST
request to /oauth/token like in the following example:
POST https://www.pathofexile.com/oauth/token
...
Content-Type: application/x-www-form-urlencoded
client_id=example
&client_secret=verysecret
&grant_type=client_credentials
&scope=service:psapi
-
On success you will receive a response with an access token:
{
"access_token": "cded8a4638ae9bc5fe6cd897890e25e41f0f4e21",
"expires_in": null,
"token_type": "bearer",
"username": "Novynn",
"sub": "c5b9c286-8d05-47af-be41-67ab10a8c53e",
"scope": "service:psapi"
}
-
Please note: tokens generated via the Client Credentials method have their identity set to the registered owner of the application.
This means that tokens with appropriate scopes will have access your account details. It is extremely important that you keep your client credentials a secret.
The owning account will also be used for rate-limiting endpoints where appropriate.
Refresh Token Grant
If your application has access to the refresh token grant type then you will receive an additional refresh_token
property at the final step of the authorization code grant.
This token lasts for 90 days and can be exchanged to generate a new access token without requesting the user's consent again.
Flow:
-
Submit a request for a new access token using the
refresh_token
grant:
-
Send a
POST
request to /oauth/token like in the following example:
POST https://www.pathofexile.com/oauth/token
...
Content-Type: application/x-www-form-urlencoded
client_id=example
&client_secret=verysecret
&grant_type=refresh_token
&refresh_token=17abaa74e599192f7650a4b89b6e9dfef2ff68cd
-
On success you will receive a response with an access token and a new refresh token:
{
"access_token": "41bcefbc2f0d6ea0fa1cce10c435310d3c475e5b",
"expires_in": 2592000,
"token_type": "bearer",
"scope": "account:profile"
"username": "Novynn",
"sub": "c5b9c286-8d05-47af-be41-67ab10a8c53e",
"refresh_token": "4e9dbe97e038430bd943d35f8d5f8bef99699396"
}
-
Please note: The new refresh token that is returned will inherit the expiry time of the used token. You cannot extend the expiration time of your refresh token in any way.
The used refresh token will also be immediately expired.
Authorizing a Request
Once you have an access token, all you need to do is include it in the Authorization
header of a request:
Authorization: Bearer 486132c90fedb152360bc0e1aa54eea155768eb9
An HTTP 401 error will occur when the token has expired or has been revoked. You will need to generate a new one.
Similarly, an HTTP 403 error occurs when using a token that does not have the correct scope for the resource. You will need to generate a new one with the correct scopes set.
Managing Tokens
As access tokens allow access to a specific user's personal information, you must be careful in how you store them. You must not share access tokens with anyone but their owner.
Since they do eventually expire it's fine to send them to the browser to store client-side in a Cookie or local storage as long as you do so using a secure method such as HTTPS.
Refresh tokens must always be stored in a secure manner server-side. If your application flow does not allow for this then refresh tokens can be turned off for your application to meet our requirements.