> For the complete documentation index, see [llms.txt](https://api-docs.gatcg.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://api-docs.gatcg.com/knowledge/using-the-grand-archive-auth-flow.md).

# Using the Grand Archive auth flow

If you're reading this you've likely been authorized to integrate Grand Archive user accounts into your application - congratulations!

### Step 1: Prompting the user to sign in

To begin the auth flow, you need to redirect the user to `https://accounts.gatcg.com`, passing in query parameters containing your application's name and redirect URI as `app` and `redirect_uri` respectively:

```javascript
const queryParams = new URLSearchParams({
  app: 'My App',
  redirect_uri: 'https://example.com/api/authorize'
});

window.location.href = (
  `https://accounts.gatcg.com?${queryParams.toString()}`
)
```

Here, my app's name is *My App* and `https://example.com` is one of my application's authorized domains.

Upon successful sign in, the user will be redirected back to the specified redirect URI with a `code` query parameter attached (see Step 2).

### Step 2: Getting the session and user information

This `code` acts as a handshake between your application and the auth flow, verifying to the auth flow that you've successfully received the user back.

You'll now want to make a `GET` request to `https://accounts.gatcg.com/session`, passing back the `code` as a query parameter.

Note that all requests made to accounts.gatcg.com require the `app` query parameter to be present.

```javascript
const queryParams = new URLSearchParams({
  app: 'My App',
  code: 'ad5dcec8f...', // The code received in Step 1.
});

const response = await fetch((
  `https://accounts.gatcg.com/session?${queryParams.toString()}`
), {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
  }
}).then(res => res.json())
```

If successful, this will give you both the session details and information about the user:

```json
{
  "session": {
    "accessToken": "Wx5+BHHdMCQBXZnhf...",
    "expires": 1752685088
  },
  "user": {
    "id": 12345,
    "permissions": [
      "my-app.some.user.permission"
    ],
    "previousIds": [1234],
    "username": "ExampleUser",
    "uuid": "308a9338-7273-4f..."
  }
}
```

Depending on what level of access you have, the user details above may contain additional information.

Note that if you're storing data about the user in your application you'll want to use their `uuid`. A user's `id` and `username` may change.

If unsuccessful, you will instead get an error back with a relevant 4XX status code:

```json
{
  "error": {
    "message": "Some error message.",
    "code": 999
  },
}
```

Note that the `code` value here cannot be reused.

### Step 3: Verifying the user's logged in state

From time to time you'll need to check if the user is still signed in, or check if something about their account has changed.

To do this, you can make a `GET` request to `https://accounts.gatcg.com/session/user`, providing the user's access token as the authorization header.

```javascript
const queryParams = new URLSearchParams({
  app: 'My App',
});

const accessToken = 'Wx5+BHHdMCQBXZnhf...' // The user's access token.

const response = await fetch((
  `https://accounts.gatcg.com/session/user?${queryParams.toString()}`
), {
  method: 'GET',
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json',
  }
}).then(res => res.json())
```

If successful, this will give you the most up to date version of the user's details:

```json
{
  "avatar": {
    "frame": "/images/avatars/frames/...",
    "image": "/images/avatars/...",
    "rarity": 1
  },
  "id": 54321,
  "permissions": [
    "my-app.some.user.permission"
  ],
  "previousIds": [12345],
  "username": "RenamedUser",
  "uuid": "308a9338-7273-4f..."
}
```

Just sake of example, the user's `id` and `username` have both changed since Step 2. Whilst username changes are not tracked, a `previousIds` array will be returned listing all previously-known IDs for that user - both ID and username changes are very rare.

If unsuccessful, you will instead get an error back with a relevant 4XX status code:

```json
{
  "error": {
    "message": "Some error message.",
    "code": 999
  },
}
```

### Refreshing a user's access token

The session's `expires` timestamp received in Step 2 denotes when their access token will expire (in seconds since Unix epoch).

You may want to refresh the token's lifetime. To do so, you can make a `GET` request to `https://accounts.gatcg.com/session/refresh`, providing the user's access token as the authorization header:

```javascript
const queryParams = new URLSearchParams({
  app: 'My App',
});

const accessToken = 'Wx5+BHHdMCQBXZnhf...' // The user's access token.

const response = await fetch((
  `https://accounts.gatcg.com/session/refresh?${queryParams.toString()}`
), {
  method: 'GET',
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json',
  }
}).then(res => res.json())
```

If successful, this will give you an updated access token:

```json
{
  "accessToken": "QKOwVYbRUsWDPvcqH...",
  "expires": 1755277088
},
```

If unsuccessful, you will instead get an error back with a relevant 4XX status code:

```json
{
  "error": {
    "message": "Some error message.",
    "code": 999
  },
}
```

A fresh access token lasts 30 days, so this isn't something you need to worry about all that often.

#### Logging a user out

To ensure a user's access token can no longer be used, a `GET` request can be made to `https://accounts.gatcg.com/session/logout`:

```javascript
const queryParams = new URLSearchParams({
  app: 'My App',
});

const accessToken = 'Wx5+BHHdMCQBXZnhf...' // The user's access token.

const response = await fetch((
  `https://accounts.gatcg.com/session/logout?${queryParams.toString()}`
), {
  method: 'GET',
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json',
  }
}).then(res => res.json())
```

If successful, this will give you a success boolean:

```json
{
  "success": true
},
```

If unsuccessful, you will instead get an error back with a relevant 4XX status code:

```json
{
  "error": {
    "message": "Some error message.",
    "code": 999
  },
}
```

### Passing additional parameters

Sometimes it may be necessary to provide additional context when taking users through the auth process.

It's possible to send up to three additional fields when redirecting users to `https://accounts.gatcg.com` (Step 1), by including `additional_parameter_1`, `additional_parameter_2` and `additional_parameter_3` query parameters:

```javascript
const queryParams = new URLSearchParams({
  app: 'My App',
  redirect_uri: 'https://example.com/api/authorize',
  additional_parameter_1: 'Foo',
  additional_parameter_2: 'Bar',
  additional_parameter_3: 'Baz',
});

window.location.href = (
  `https://accounts.gatcg.com?${queryParams.toString()}`
)
```

When the user gets redirected back to your application (Step 2), those three parameters will be included with the request:

```
https://example.com/api/authorize
 ?code=...
 &additional_parameter_1=Foo
 &additional_parameter_2=Bar
 &additional_parameter_3=Baz
```

### Error handling

Generally if an error is received through any of the above endpoints it means the user is no longer authenticated and needs to be taken back through the auth flow, however this isn't always the case and you may need to handle errors gracefully.

Every error response contains a short message describing the problem along with a code which gives more insight into what went wrong:

```json
{
  "error": {
    "message": "Some error message.",
    "code": 999
  },
}
```

Below is a list of codes which can be received, grouped by HTTP status:

#### HTTP Status 400 - Bad Request

* `40000` **Malformed request**: Required data was not provided (such as the `app` query parameter or authorization header);
* `40001` **Validation failed**: The user provided invalid data (this is handled internally);
* `40002` **Code not valid** \[`/session`]: The session code is not valid (likely malformed);
* `40003` **Code invalid application** \[`/session`]: The session code is not valid for this application;
* `40004` **Code invalid user** \[`/session`]: The session code does not match the signed in user;
* `40006` **Access token not valid**: The access token is not valid (likely malformed);
* `40006` **Access token invalid application**: The access token is not valid for this application;
* `40007` **Access token invalid user**: The access token is not valid for this user;

#### HTTP Status 401 - Unauthorized

* `40100` **Access token expired**: The user's access token has expired (prompt them to sign in again);
* `40101` **Access token missing**: The user's access token was not provided (check what's being sent through the authorization header (`40000` is the expected error here - this exists as a failsafe));
* `40102` **Session revoked**: The user's session has been revoked (prompt them to sign in again);
* `40102` **Session refresh failed** \[`/session/refresh`]: The user's session refresh token did not work for a variety of reasons (prompt them to sign in again);

#### HTTP Status 403 - Forbidden

* `40300` **Code already used** \[`/session`]: The session code has already been used;
* `40301` **User disallowed action**: The user attempted to perform an action they do not have access to (this is handled internally);

#### HTTP Status 404 - Not Found

* `40400` **User not found**: The user could not be found (this is a fail-safe - this should never happen);
* `40401` **User data mismatch**: The user's immutable data has changed (this is a fail-safe - this should never happen);
* `40402` **Session not found**: The user's session could not be found (this is a fail-safe - this should never happen);
* `40403` **Session refresh code missing** \[`/session/refresh`]: The user's session has no refresh token (this is a fail-safe - this should never happen);

#### HTTP Status 409 - Conflict

* `40900` **Data conflict**: Data could not be updated due to a conflict (this is handled internally);

#### HTTP Status 500 - Internal Server Error

* `50000` **Internal server error**: An unexpected internal server error occurred. This should never happen, but if it does please reach out to us so we can help debug the problem.

### User profile pictures

All Grand Archive user accounts have profile picture images associated with them. This information is returned as part of the `avatar` object contained in the `https://accounts.gatcg.com/session/user` response:

```json
{
  "frame": "/images/avatars/frames/73eb9e40-853f-4b69-be69-aa18b8b79fb9.jpg",
  "image": "/images/avatars/a09d7625-1db0-4750-8108-50f32373446a.jpg"
}
```

The `image` and `frame` paths here are relative to `https://accounts.gatcg.com`, i.e. `https://accounts.gatcg.com/images/avatars/....jpg`.

The icon images (`image`) are exactly 256x256px whilst frames (`frame`) are exactly 512x512px.

Most use cases for profile pictures will only require the main icon image, but should you wish to use frames as well for additional flair these are overlaid on top of icons using the following formula:

```javascript
const ICON_SIZE = 64; // 64px (example)
const FRAME_SIZE = ICON_SIZE / 93 * 128; // 64 / 93 * 128 = 88.086px
const FRAME_POSITION_Y = ICON_SIZE / -24; // 64 / -24 = -2.667px
```

That is to say, when overlaying a profile picture icon and frame directly on top of one another, an icon at 64px would require the frame to be resized to 88.086px and shifted up by 2.667px to perfectly cover the icon.

<figure><img src="/files/9UB5z1rb0mR3kpaDdwv7" alt=""><figcaption></figcaption></figure>

Finally the `rarity` property denotes how rare the profile picture icon is. These values have no expected impact on the display of the icon or frame, but should you wish to use this for whatever reason the values are mapped as follows:

* `1` = Common
* `2` = Uncommon
* `3` = Rare
* `4` = Super Rare
* `5` = Ultra Rare
* `6` = Promotional Rare


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://api-docs.gatcg.com/knowledge/using-the-grand-archive-auth-flow.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
