Skip to content
codeflush-dev edited this page Nov 27, 2021 · 7 revisions

GW2Auth Developer Guide

Creating a client

To be able to request a users authorization, you first have to create a client. To do this, login at GW2Auth and navigate inside the Account-Management to Clients and click the button Register a new Client.

Choose a name for your client (this name will be displayed to the users) and fill in the redirect uri. For local testing purposes, use http://127.0.0.1. localhost is not allowed. If you want to see how an authorization would look like, you can use https://gw2auth.com/account/client/debug

Once you have filled in all required values, click Create Client. You will now see an overview of your newly created client.

Make sure to copy the Client-Secret on this page, since it can't be displayed afterwards. Never give your Client-Secret to anyone else.

GW2Auth integration

GW2Auth uses OAuth2.0 to authorize clients. For most web frameworks, you'll find an existing implementation which takes care of all the details. However, the following guide will show you the basics of how it works.

OAuth2 Endpoints

All relevant OAuth2.0 URLs are present in https://gw2auth.com/.well-known/oauth-authorization-server Most importantly, the following:

Key Description
authorization_endpoint Users have to be redirected to this Endpoint to initiate an authorization
token_endpoint This Endpoint has to be used in your backend to retrieve tokens for either an initiated authorization or to retrieve new tokens using an Refresh Token
jwks_uri This Endpoint should be used in your backend to retrieve tokens for either an initiated authorization or to retrieve new tokens using an Refresh Token

Initial authorization

During the initial authorization, the user which should authorize your client is required to be active. They have to actively authorize your client by selecting the GW2-Accounts they want to give your client access to.

Generating a state-parameter on your side

For each authorization request, you should generate a random state-parameter on your side. Keep this randomly generated value in some store (in-memory, database, whatever your like). Note that an authorization can technically not be ensured to be fulfilled (a user may simply close the browser for example). So keep in mind to you cleanup unfulfilled authorizations at some point.

Generally, this state-parameter should be a randomly generated string to recognize the initiated authorization once it comes back to you.

Choose the scopes you want to have access to

The following scopes are supported for all clients at GW2Auth:

Scope Description
gw2:account GW2-API "account" permission for all GW2-Accounts selected by the user
gw2:builds GW2-API "builds" permission ...
gw2:characters GW2-API "characters" permission ...
gw2:guilds GW2-API "guilds" permission ...
gw2:inventories GW2-API "inventories" permission ...
gw2:progression GW2-API "progression" permission ...
gw2:pvp GW2-API "pvp" permission ...
gw2:tradingpost GW2-API "tradingpost" permission ...
gw2:unlocks GW2-API "unlocks" permission ...
gw2:wallet GW2-API "wallet" permission ...
gw2auth:verified Adds an additional field "verified" for all GW2-Accounts selected by the user. This represents the users GW2-Account-Verification status at GW2Auth (more information below)

Redirect the user to the authorization_endpoint

Next, you should redirect the user to the authorization_endpoint using the following parameters passed in the query:

Query Parameter Description Example Value
response_type Must be code code
client_id The Client-ID of your Client d5dba13c-42d7-4c78-b6ea-9bcb7407112b
state The state-parameter you generated on your side (see above) ioasho889dasdknadjhiahdiohi1290asin
scope The list of scopes you want to request (see above), separated by space. Must not be empty. In any order. gw2:account gw2auth:verified
redirect_uri The redirect URI you used when creating the client https://gw2auth.com/account/client/debug
name (Optional) A display name for this Authorization. If not passed, the internal authorization ID will be shown instead. Only pass this if you can provide a meaningful name - for client-side applications this could be the name of the current machine for example. DESKTOP-12345

The user will now be shown a dialog where they have to select all their GW2-Accounts which they want your client give access to.

Important note: Due to the nature of redirects (they're handled on the client side), a user may take the Location-Header of your redirect, keep the state parameter but modify the scope-Parameter. We will come back to this below.

Waiting for the authorization response

Once the user either approved or declined the requested authorization, they will be redirected to the URI given in the initial request.

If the user declined the authorization (by clicking Cancel on the authorization page), the following Query Parameters will be present in the request:

Query Parameter Description Example Value
error An OAuth2 Error-Code access_denied
error_description A detailed description of the error The user has denied your application access.

If the user approved the authorization (by selecting at least one GW2-Account and clicking Authorize), the following Query Parameters will be present in the request:

Query Parameter Description Example Value
code A short-lived one time code which can be used to retrieve the initial Refresh- and Access-Token wGS4oW0Dm8hPxlY9EF3lhRBeXvBAoQu2iLgwONa2CaVqftHog0dPJ4zCOnFkFkVWQXZbLYH434iGuJFScNOvQgAlrw8ZsO6hquFxSG7y3HUpSWKrXl3IBF4-UOzatEP-
state The state-Parameter passed to the redirection in the step before ioasho889dasdknadjhiahdiohi1290asin

Retrieving the initial Refresh- and Access-Token

While processing the request above, your backend should use the passed code-Parameter to retrieve the initial Refresh- and Access-Token.

To do this, perform a POST-Request to the token_endpoint mentioned above and pass the following Query-Parameters:

Query Parameter Description Example Value
grant_type Must be authorization_code authorization_code
code The code-Parameter given to the request you're currently processing (see above) wGS4oW0Dm8hPxlY9EF3lhRBeXvBAoQu2iLgwONa2CaVqftHog0dPJ4zCOnFkFkVWQXZbLYH434iGuJFScNOvQgAlrw8ZsO6hquFxSG7y3HUpSWKrXl3IBF4-UOzatEP-
client_id The Client-ID of your Client d5dba13c-42d7-4c78-b6ea-9bcb7407112b
client_secret The Client-Secret of your Client (the one you copied right after creating your client) Sx9skfRMXxIVfX7UWaktKP9od1pV7kLGDSBzdsvZIZ1xdApzrOHTfom6m8XNrpVa
redirect_uri The exact same redirect_uri that has been passed to the initial authorization request https://gw2auth.com/account/client/debug

A successful response will look like this:

{
   "access_token": "" // Access-Token (JWT),
   "refresh_token": "uVKRO-gElNXaAF_VNg-6u8jbmtlazLDNC3ljPiX92rCY3j59Oe6Lt3V2PnZJZEny6ZMUQ8FCZkjzLMfXrNgymvBLW4RYEpPSLb7QRX5QtPaGIhqsXKcufJrX3jR1bJBw",// the Refresh Token used to retrieve new Access Tokens (without user interaction)
   "scope":"gw2auth:verified gw2:account",// the authorized scopes (see important note below)
   "token_type": "Bearer",
   "expires_in": 1799 // seconds until the Access-Token expires
}

Important note: As mentioned above, a user can potentionally manipulate the scopes passed in the initial redirect. Make sure to verify the scope-Value here!

Persist the refresh_token as you wish. This token can be used to request new Refresh- and Access-Tokens. Access-Tokens are valid for 30 minutes, while Refresh-Tokens are valid for 180 days. You always have to use the latest Refresh-Token.

Reading the GW2-API-Subtokens out of the Access-Token

Access-Tokens returned by GW2Auth are JWTs. The payload of these JWTs is a JSON containing the following values:

JSON-Key JSON-Type Description Example Value
sub string A unique identifier for the GW2Auth-Account of the user. This value is not consistent across different clients. 1f8f5637-8b14-4291-825a-76780440befd
scope list of strings The list of authorized scopes ["gw2:account", "gw2auth:verified"]
iss string A URL of the issuer which created this Access-Token https://gw2auth.com
iat number UNIX-Timestamp (seconds): Timestamp at which this token was issued 1635810481
exp number UNIX-Timestamp (seconds): Timestamp at which this token will expire 1635812281
gw2:permissions list of strings The list of authorized GW2-API-Permissions ["account"]
gw2:tokens object A JSON-Object containing all subtokens (and some additional information) for all by the user authorized GW2-Accounts. Key: GW2-Account-ID ; Value: Token-Object (see below) {"93DF54C6-78F7-E111-809D-78E7D1936EF0": {...}}
The Token-Object:
JSON-Key JSON-Type Description Example Value
name string The name of the GW2-Account, freely chosen by the user at GW2Auth Felix.9127 (Main)
token string The GW2-API-Subtoken, valid for exactly the same time as the Access-Token itself. Use this to perform GW2-API-Requests. Only present if error is not present. ...
error string An error description if, for any reason, no subtoken could be retrieved for this GW2-Account. Only present if token is not present. ...
verified boolean Only present if the scope gw2auth:verified was requested (and authorized) true
Clone this wiki locally