> For the complete documentation index, see [llms.txt](https://developers-apps-in-toss.toss.im/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers-apps-in-toss.toss.im/guide/en/authentication/migration.md).

# Toss Login Migration

**Toss Login(`userKey`)** mini apps that use **User identification key (`hash`)** to transition to.

If you follow this document, you can gradually map users currently using Toss Login to the user identification key, and once all users have been migrated, you can completely remove the Toss Login dependency.

### When should you use this guide?

* Existing Toss Login `userKey` are being used for user identification.
* Going forward, the user identification key `hash`value is the standard identifier you want to use.

### Key concepts

* **User identification key hash**: `getUserKeyForGame()` A unique game identifier issued by calling
* **Toss Login userKey**: Existing user identifier based on Toss Login
* **Mapping**: linking the same user's `userKey` and `hash` values one-to-one

{% hint style="info" %}
**Please note**

For each game, `hash` the value is different.
{% endhint %}

### Overall migration flow

1. On the client, `getUserKeyForGame()` issue the user identification key `hash` value using
2. `getIsTossLoginIntegratedService()` to check whether Toss Login is integrated.
3. Check mapping status on the partner company's server.
4. If it is not mapped, `appLogin()` perform Toss Login through `hash` and send the value to the server.
5. On the server, Toss Login `userKey` and user identification key `hash` store the values in the mapping table.
6. After that, `hash` users can be identified with only the value. Once all users are mapped, remove the Toss Login dependency.

### APIs that need to be implemented in advance

Partners must **implement the following two APIs** These APIs are not provided by Apps in Toss, so please develop them yourself on the partner company's server, referring to the examples below.

* **Check mapping status**
  * `POST /api/auth/migration/status`
  * **Req**: `{ hash: string }`
  * **Res**: `{ isMapped: boolean }`
* **Create mapping**
  * `POST /api/auth/migration/link`
  * **Req**: `{ hash: string; authorizationCode: string; referrer?: string }`
  * **Res**: `{ success: true }`

***

### Client implementation steps

#### 1. Import the SDK

```tsx
import { getUserKeyForGame, getIsTossLoginIntegratedService, appLogin } from '@apps-in-toss/web-framework';
```

#### 2. Issue game hash value

```tsx
const result = await getUserKeyForGame();
if (!result) return console.warn('Unsupported app version.');
if (result === 'INVALID_CATEGORY') return console.error('This mini app is not in the game category.');
if (result === 'ERROR') return console.error('An error occurred while retrieving the user key.');
if (result.type !== 'HASH') return console.error('Unknown return value.');
const { hash } = result;
```

#### 3. Check whether Toss Login is integrated

```tsx
const status = await getIsTossLoginIntegratedService();
if (status === 'INVALID_CLIENT') {
  console.log('This mini app does not have Toss Login integrated.');
  return;
}
```

For the detailed API specification, refer to [`getIsTossLoginIntegratedService`](#%ED%86%A0%EC%8A%A4-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EC%97%B0%EB%8F%99-%EC%97%AC%EB%B6%80-%ED%99%95%EC%9D%B8%ED%95%98%EA%B8%B0) section below.

#### 4. Check mapping status and map on the partner company's server

```tsx
if (status === true) {
  // User with Toss Login integrated
  const { isMapped } = await fetch('/api/auth/migration/status', {
    // Check mapping status
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ hash }),
  }).then((r) => r.json());

  if (!isMapped) {
    const { authorizationCode, referrer } = await appLogin(); // If unmapped, create mapping after Toss Login
    await fetch('/api/auth/migration/link', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ authorizationCode, referrer, hash }),
    });
  }

  console.log('Mapping complete or already mapped user.');
  return;
}

console.log('User without Toss Login integration.'); // status === false
```

#### 5. Use the user identification key hash

Now user identification can be based on the user identification key `hash`value. Instead of Toss Login, `userKey` use `getUserKeyForGame()` the user identification key issued with `hash`value as the user identifier on both the server and client.

***

### Full example code

```tsx
import { getUserKeyForGame, getIsTossLoginIntegratedService, appLogin } from '@apps-in-toss/web-framework';

async function migrateIfNeeded() {
  const res = await getUserKeyForGame();
  if (!res) return console.warn('Unsupported app version.');
  if (res === 'INVALID_CATEGORY') return console.error('This mini app is not in the game category.');
  if (res === 'ERROR') return console.error('An error occurred while retrieving the user key.');
  if (res.type !== 'HASH') return console.error('Unknown return value.');
  const { hash } = res;

  let status: boolean;
  try {
    status = await getIsTossLoginIntegratedService();
  } catch (error: any) {
    console.error('Error checking whether Toss Login is integrated:', error);
    return;
  }

  if (status === true) {
    // Check mapping status
    const { isMapped } = await fetch('/api/auth/migration/status', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ hash }),
    }).then((r) => r.json());

    if (!isMapped) {
      // If unmapped, create mapping after Toss Login
      const { authorizationCode, referrer } = await appLogin();

      await fetch('/api/auth/migration/link', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ authorizationCode, referrer, hash }),
      });
    }

    console.log('Mapping complete or already mapped user.');
    return;
  }

  // status === false : Toss Login feature exists, but current user is not integrated
  console.log('User without Toss Login integration.');
}
```

{% hint style="info" %}
**Exception handling**

In a mini app that does not use Toss Login, `getIsTossLoginIntegratedService()`calling can cause the following exception.

```tsx
@throw {message: "oauth2ClientId setup is required."}
```

In this case, the environment does not have Toss Login functionality, so no separate handling is needed.
{% endhint %}

***

### Check whether Toss Login is integrated

**SDK function:** `getIsTossLoginIntegratedService`

`getIsTossLoginIntegratedService`is **an API that checks whether the current user is integrated with Toss Login**.

This function is mainly used **during the migration process from Toss Login to user identification key issuance**. Depending on whether the user is an existing Toss Login user, you can use it to branch login flows or data migration handling.

**Signature**

```tsx
function getIsTossLoginIntegratedService(): Promise<boolean>;
```

| Return type        | Description                                                                                |
| ------------------ | ------------------------------------------------------------------------------------------ |
| `Promise<boolean>` | If the current service is integrated with Toss Login `true`, otherwise `false`is returned. |

#### Notes

* This API is only meaningful for mini apps that use (or used to use) Toss Login.
* If called from a mini app that never uses Toss Login, an exception like the one below may occur.

```tsx
@throw { message: 'oauth2ClientId setup is required.' }
```

**Example: Check whether Toss Login is integrated**

The example below shows a basic flow that checks whether the user is a Toss Login integration user and then handles each status differently.

{% tabs %}
{% tab title="js" %}

```js
import { getIsTossLoginIntegratedService } from '@apps-in-toss/web-framework';

async function handleGetIsTossLoginIntegratedService() {
  try {
    const result = await getIsTossLoginIntegratedService();

    if (result === undefined) {
      console.warn('Unsupported app version.');
      return;
    }
    if (result === true) {
      console.log('The user is integrated with Toss Login.');
      // You can handle Toss Login integrated users here.
    }
    if (result === false) {
      console.log('The user is not integrated with Toss Login.');
      // You can handle cases where the user is not integrated with Toss Login here.
    }
  } catch (error) {
    console.error(error);
  }
}
```

{% endtab %}

{% tab title="React" %}

```tsx
import { getIsTossLoginIntegratedService } from '@apps-in-toss/web-framework';

function GetIsTossLoginIntegratedServiceButton() {
  async function handleClick() {
    try {
      const result = await getIsTossLoginIntegratedService();

      if (result === undefined) {
        console.warn('Unsupported app version.');
        return;
      }
      if (result === true) {
        console.log('The user is integrated with Toss Login.');
        // You can handle Toss Login integrated users here.
      }
      if (result === false) {
        console.log('The user is not integrated with Toss Login.');
        // You can handle cases where the user is not integrated with Toss Login here.
      }
    } catch (error) {
      console.error(error);
    }
  }

  return <button onClick={handleClick}>Check whether Toss Login integrated service is enabled</button>;
}
```

{% endtab %}

{% tab title="React Native" %}

```tsx
import { Button } from 'react-native';
import { getIsTossLoginIntegratedService } from '@apps-in-toss/framework';

function GetIsTossLoginIntegratedServiceButton() {
  async function handlePress() {
    try {
      const result = await getIsTossLoginIntegratedService();

      if (result === undefined) {
        console.warn('Unsupported app version.');
        return;
      }
      if (result === true) {
        console.log('The user is integrated with Toss Login.');
        // You can handle Toss Login integrated users here.
      }
      if (result === false) {
        console.log('The user is not integrated with Toss Login.');
        // You can handle cases where the user is not integrated with Toss Login here.
      }
    } catch (error) {
      console.error(error);
    }
  }

  return <Button onPress={handlePress} title="Check whether Toss Login integrated service is enabled" />;
}
```

{% endtab %}
{% endtabs %}

#### When is it good to use?

* In a Toss Login-based service **switching to user identification key** when
* distinguishing between existing and new users **data migration/compensation processing**when you need to do
* depending on whether Toss Login is integrated, **provide different UX**when you need to

#### Notes

* `getIsTossLoginIntegratedService`is a migration support API.
* For authentication/login functionality, refer to the following.
  * Toss Login
  * [Issuing a user identification key](https://appsintoss.gitbook.io/appsintoss-docs/documentation/common/authentication/hash-key)


---

# 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://developers-apps-in-toss.toss.im/guide/en/authentication/migration.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.
