> 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`)** a mini app that uses **User identification key(`hash`)** explains how to switch to using hash.

Following this document, you can gradually map users currently using Toss Login to user identification keys, 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 using it for user identification.
* In the future, user identification key `hash`I want to use the value as the standard identifier.

### Key concepts

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

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

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

### Overall migration flow

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

### APIs that require pre-implementation

The partner company must **implement the following two APIs directly.** These APIs are not provided by Apps in Toss; please refer to the examples below and develop them yourself on the partner company's server.

* **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 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 looking up 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 is not integrated with Toss Login.');
  return;
}
```

For detailed API specifications, see the [`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 partner company's server

```tsx
if (status === true) {
  // user integrated with Toss Login
  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 not mapped, perform Toss Login and create mapping
    await fetch('/api/auth/migration/link', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ authorizationCode, referrer, hash }),
    });
  }

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

console.log('User is not integrated with Toss Login.'); // status === false
```

#### 5. Use user identification key hash

Now user identification can be based on user identification key `hash`value. Toss Login `userKey` instead, `getUserKeyForGame()` the user identification key issued with `hash`please use the value as the user identifier on both 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 looking up 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 while 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 not mapped, perform Toss Login and create mapping
      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 completed or user is already mapped.');
    return;
  }

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

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

In a mini app that does not use Toss Login `getIsTossLoginIntegratedService()`calling this may cause the exception below.

```tsx
@throw {message: "oauth2ClientId configuration 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 in **the migration process from Toss Login to issuing user identification keys**and can be used to branch login flows or data migration handling depending on whether the user is an existing Toss Login user.

**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 in mini apps that use (or used) Toss Login.
* Calling it in a mini app that never uses Toss Login may cause the exception below.

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

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

The example below shows a basic flow that checks whether the user is a Toss Login integrated user, then performs different actions depending on the status.

{% 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 the case 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 the case where the user is not integrated with Toss Login here.
      }
    } catch (error) {
      console.error(error);
    }
  }

  return <button onClick={handleClick}>Check Toss Login integrated service status</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 the case where the user is not integrated with Toss Login here.
      }
    } catch (error) {
      console.error(error);
    }
  }

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

{% endtab %}
{% endtabs %}

#### When is it useful?

* In a Toss Login-based service **switching (migration) to a user identification key** when
* distinguishing existing users from new users **data migration/compensation handling**when needed
* depending on whether Toss Login is integrated **providing different UX**when needed

#### Notes

* `getIsTossLoginIntegratedService`is a migration support API.
* For authentication/login features, please refer to the following.
  * Toss Login
  * [Issuing 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.
