# 인증

**URL:** https://heroiclabs.com/docs/kr/nakama/concepts/authentication/
**Summary:** 사용자는 서버와 상호 작용하기 전에 인증해야 합니다. 이 인증은 사용자의 장치, 이메일, 다양한 소셜 공급자 또는 사용자 지정 솔루션을 사용하여 수행할 수 있습니다. 인증 방법을 연결하면 여러 로그인을 지원하고 여러 장치에서 사용자를 식별할 수 있습니다.

---


# 인증

서버에는 기본 제공 인증이 있으므로 클라이언트는 [서버 키](../../getting-started/configuration/#socket.server_key)가 있는 경우에만 요청을 보내고 연결할 수 있습니다. 기본 서버 키는 `defaultkey`이지만 [고유한 값](../../getting-started/configuration/#socket)을 설정하는 것이 매우 중요합니다. 이 값은 클라이언트 코드에 포함되어야 합니다.

인증이 성공하면 클라이언트는 [사용자](../user-accounts/)로 세션을 만들 수 있습니다.

<!-- more -->

{{< code type="client" >}}
```javascript
var useSSL = false;
var client = new nakamajs.Client("defaultkey", "127.0.0.1", 7350, useSSL);
```
{{< / code >}}

{{< code type="client" >}}
```csharp
// Use "https" scheme if you've setup SSL.
var client = new Client("http", "127.0.0.1", 7350, "defaultkey");
```
{{< / code >}}

{{< code type="client" >}}
```cpp
NClientParameters parameters;
parameters.serverKey = "defaultkey";
parameters.host = "127.0.0.1";
parameters.port = DEFAULT_PORT;
NClientPtr client = createDefaultClient(parameters);
```
{{< / code >}}

{{< code type="client" >}}
```java
Client client = new DefaultClient("defaultkey", "127.0.0.1", 7349, false)
// or same as above.
Client client = DefaultClient.defaults("defaultkey");
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
onready var client := Nakama.create_client("defaultkey", "127.0.0.1", 7350, "http")
```
{{< / code >}}

{{< code type="client" framework="defold">}}
```lua
local defold = require "nakama.engine.defold"

local config = {}
config.host = 127.0.0.1
config.port = 7350
config.use_ssl = false
config.username = "defaultkey"
config.engine = defold

local client = nakama.create_client(config)
```
{{< / code >}}

모든 사용자 계정은 [인증에 사용되는 옵션](#authenticate) 중 하나에서 생성됩니다. 사용자 계정에 액세스하는 방법이기 때문에 이러한 각 옵션을 "연결"라고 합니다. 각 계정에 하나 이상의 연결을 추가할 수 있어 사용자가 다양한 장치에서 다양한 방법으로 로그인할 수 있습니다.

## 인증

서버와 상호 작용하기 전에, 시스템 인증을 통해 세션 토큰을 얻어야 합니다. 인증 시스템은 매우 유연합니다. 이메일 주소로 사용자를 등록하고 Facebook 계정을 [연결](#link-or-unlink)하여 다른 장치에서 로그인하는 데 사용할 수 있습니다.

기본적으로 인증에 사용된 식별자가 이전에 시스템에 없는 경우 시스템은 사용자를 자동으로 생성합니다. 이 패턴은 [장치](#device) 섹션에 표시됩니다.

각 클라이언트의 등록 및 로그인을 처리하는 가장 좋은 방법에 대한 모든 예를 보려면 [가이드](../../client-libraries/)를 참조하십시오.

### 장치

장치 식별자를 사용하면 서버에 사용자를 눈에 띄지 않게 등록할 수 있습니다. 문제 없는 사용자 경험을 제공하지만 장치 식별자가 장치 업데이트를 변경할 수도 있기 때문에 신뢰할 수 없습니다.

계정을 만들 때 사용자 지정 사용자 이름을 선택할 수 있습니다. 이렇게 하려면 `username`을(를) 사용자 지정 이름으로 설정합니다. 사용자 계정을 암시적으로 만들지 않고 `create`만 인증하려면 false로 설정합니다.

장치 식별자는 대시가 있는 영숫자 문자를 포함해야 하며 10 ~ 128 바이트여야 합니다.

{{< code type="client" >}}
```bash
curl "http://127.0.0.1:7350/v2/account/authenticate/device?create=true&username=mycustomusername" \
  --user 'defaultkey:' \
  --data '{"id":"uniqueidentifier"}'
```
{{< / code >}}

{{< code type="client" >}}
```shell
POST /v2/account/authenticate/device?create=true&username=mycustomusername
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Basic base64(ServerKey:)
{
  "id": "uniqueidentifier"
}
```
{{< / code >}}

{{< code type="client" >}}
```javascript
// This import is only required with React Native
var deviceInfo = require('react-native-device-info');
var deviceId = null;

try {
  const value = await AsyncStorage.getItem('@MyApp:deviceKey');

  if (value !== null){
    deviceId = value
  }
  else {
    deviceId = deviceInfo.getUniqueID();

    AsyncStorage.setItem('@MyApp:deviceKey', deviceId).catch(function(error){
      console.log("An error occurred: %o", error);
    });
  }
}
catch (error) {
  console.log("An error occurred: %o", error);
}

var create = true;
const session = await client.authenticateDevice(deviceId, create, "mycustomusername");
console.info("Successfully authenticated:", session);
```
{{< / code >}}

{{< code type="client" >}}
```csharp
// Should use a platform API to obtain a device identifier.
var deviceId = System.Guid.NewGuid().ToString();
var session = await client.AuthenticateDeviceAsync(deviceId);
System.Console.WriteLine("New user: {0}, {1}", session.Created, session);
```
{{< / code >}}

{{< code type="client" >}}
```cpp
auto loginFailedCallback = [](const NError& error)
{
};

auto loginSucceededCallback = [](NSessionPtr session)
{
    cout << "Successfully authenticated" << endl;
};

std::string deviceId = "unique device id";

client->authenticateDevice(deviceId, opt::nullopt, opt::nullopt, {}, loginSucceededCallback, loginFailedCallback);
```
{{< / code >}}

{{< code type="client" >}}
```java
String id = UUID.randomUUID().toString();
Session session = client.authenticateDevice(id).get();
System.out.format("Session: %s ", session.getAuthToken());
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
# Unique ID is not supported by Godot in HTML5, use a different way to generate an id, or a different authentication option.
var deviceid = OS.get_unique_id()
var session : NakamaSession = yield(client.authenticate_device_async(deviceid), "completed")

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
```
{{< / code >}}

{{< code type="client" framework="defold">}}
```lua
-- login using the token and create an account if the user
-- doesn't already exist
local result = client.authenticate_device(defold,uuid(), nil, true, "mycustomusername")

if not result.token then
  print("Unable to login")
end

-- store the token and use it when communicating with the server
client.set_bearer_token(result.token)
```
{{< / code >}}

게임에서는 [Google](#google) 또는 [게임 센터](#game-center)를 사용하여 사용자를 눈에 띄지 않게 등록하는 것이 더 좋을 수 있습니다.

### 이메일

사용자는 이메일 및 암호로 등록할 수 있습니다. 암호는 데이터베이스 서버에 저장되기 전에 해시되며 관리자가 읽거나 "복구"할 수 없습니다. 따라서 사용자의 개인 정보가 보호됩니다.

계정을 만들 때 사용자 지정 사용자 이름을 선택할 수 있습니다. 이렇게 하려면 `username`을(를) 사용자 지정 이름으로 설정합니다. 사용자 계정을 암시적으로 만들지 않고 `create`만 인증하려면 false로 설정합니다.

이메일 주소는 RFC-5322에 의해 정의된 대로 유효해야 하며 암호는 8자 이상이어야 합니다.

{{< code type="client" >}}
```bash
curl "http://127.0.0.1:7350/v2/account/authenticate/email?create=true&username=mycustomusername" \
  --user 'defaultkey:' \
  --data '{"email":"email@example.com", "password": "3bc8f72e95a9"}'
```
{{< / code >}}

{{< code type="client" >}}
```shell
POST /v2/account/authenticate/email?create=true&username=mycustomusername
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Basic base64(ServerKey:)
{
  "email": "email@example.com",
  "password": "3bc8f72e95a9"
}
```
{{< / code >}}

{{< code type="client" >}}
```javascript
const email = "email@example.com";
const password = "3bc8f72e95a9";
const create = true;
const session = await client.authenticateEmail(email, password, create, "mycustomusername");
console.info("Successfully authenticated:", session);
```
{{< / code >}}

{{< code type="client" >}}
```csharp
const string email = "email@example.com";
const string password = "3bc8f72e95a9";
var session = await client.AuthenticateEmailAsync(email, password);
System.Console.WriteLine("New user: {0}, {1}", session.Created, session);
```
{{< / code >}}

{{< code type="client" >}}
```cpp
auto successCallback = [](NSessionPtr session)
{
    std::cout << "Authenticated successfully. User ID: " << session->getUserId() << std::endl;
};

auto errorCallback = [](const NError& error)
{
};

string email = "email@example.com";
string password = "3bc8f72e95a9";
string username = "mycustomusername";
bool create = true;
client->authenticateEmail(email, password, username, create, {}, successCallback, errorCallback);
```
{{< / code >}}

{{< code type="client" >}}
```java
String email = "email@example.com";
String password = "3bc8f72e95a9";
Session session = client.authenticateEmail(email, password).get();
System.out.format("Session: %s ", session.getAuthToken());
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
var email = "email@example.com"
var password = "3bc8f72e95a9"
var session : NakamaSession = yield(client.authenticate_email_async(email, password, "mycustomusername", true), "completed")

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
```
{{< / code >}}

{{< code type="client" framework="defold">}}
```lua
local result = client.authenticate_email("email@example.com", "3bc8f72e95a9", nil, true, "mycustomusername")

if not result.token then
  print("Unable to login")
end

-- store the token and use it when communicating with the server
client.set_bearer_token(result.token)
```
{{< / code >}}

### 소셜 공급자

이 서버는 등록 및 로그인하는 경우 다양한 사회 서비스를 지원합니다. 각 공급자와 함께 소셜 서비스에서 사용자 계정을 가져와 사용자를 설정하는 데 사용됩니다. 경우에 따라 사용자의 [친구](../friends/)도 가져와 친구 목록에 추가됩니다.

공급자와 함께 사용자로 등록하거나 로그인하려면 해당 소셜 서비스에서 OAUTH 또는 액세스 토큰을 구해야 합니다.

#### Apple

애플리케이션에서 [Apple로 로그인](https://developer.apple.com/sign-in-with-apple/get-started/)을 통합하려면 Apple Developer 문서를 참조하십시오.

계정을 만들 때 사용자 지정 사용자 이름을 선택할 수 있습니다. 이렇게 하려면 `username`을(를) 사용자 지정 이름으로 설정합니다. 사용자 계정을 암시적으로 만들지 않고 `create`만 인증하려면 false로 설정합니다.

{{< code type="client" >}}
```bash
curl "http://127.0.0.1:7350/v2/account/authenticate/apple?create=true&username=mycustomusername" \
  --user 'defaultkey:' \
  --data '{"token":"..."}'
```
{{< / code >}}

{{< code type="client" >}}
```shell
POST /v2/account/authenticate/apple?create=true&username=mycustomusername
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Basic base64(ServerKey:)
{
  "token": "...",
}
```
{{< / code >}}

{{< code type="client" >}}
```javascript
const token = "...";
const create = true;
const username = "...";
const session = await client.authenticateApple(token, create, username);
console.info("Successfully authenticated: %o", session);
```
{{< / code >}}

{{< code type="client" >}}
```csharp
var username = "...";
var token = "...";

var session = await client.AuthenticateAppleAsync(token, username);
System.Console.WriteLine("New user: {0}, {1}", session.Created, session);
```
{{< / code >}}

{{< code type="client" >}}
```cpp
auto successCallback = [](NSessionPtr session)
{
    std::cout << "Authenticated successfully. User ID: " << session->getUserId() << std::endl;
};

auto errorCallback = [](const NError& error)
{
};

std::string username = "...";
std::string token = "...";

client->authenticateApple(token, username);
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
var username = "..."
var token = "..."

var session : NakamaSession = yield(client.authenticate_apple_async(token, username), "completed")

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
```
{{< / code >}}

{{< code type="client" framework="defold">}}
```lua
-- Use https://defold.com/assets/siwa/
local token = "..."
local username = "..."
local result = client.authenticate_apple(token, username)

if not result.token then
  print("Unable to login")
end

-- store the token and use it when communicating with the server
client.set_bearer_token(result.token)
```
{{< / code >}}

#### Facebook

Facebook을 사용하려면 프로젝트에 Facebook SDK를 추가해야 합니다. <a href="https://developers.facebook.com/docs/" target="\_blank">온라인으로 다운로드함</a>. 코드 통합 방법에 대한 가이드를 준수합니다. 모바일 프로젝트를 사용하면 iOS 및 Android 구성 방법에 대한 지침을 따라야 합니다.

계정을 만들 때 사용자 지정 사용자 이름을 선택할 수 있습니다. 이렇게 하려면 `username`을(를) 사용자 지정 이름으로 설정합니다. 사용자 계정을 암시적으로 만들지 않고 `create`만 인증하려면 false로 설정합니다.

인증할 때 선택적으로 Facebook 친구를 Nakama의 [친구 그래프](../friends/)로 가져올 수 있습니다. 이렇게 하려면 `import`을(를) True로 설정합니다.

{{< code type="client" >}}
```bash
curl "http://127.0.0.1:7350/v2/account/authenticate/facebook?create=true&username=mycustomusername&import=true" \
    --user 'defaultkey:' \
    --data '{"token":"valid-oauth-token"}' # Supports the use of both OAuth and Facebook Limited Login (JWT) tokens.
```
{{< / code >}}

{{< code type="client" >}}
```shell
POST /v2/account/authenticate/facebook?create=true&username=mycustomusername&import=true
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Basic base64(ServerKey:)
{
  "token": "...",
}
```
{{< / code >}}

{{< code type="client" >}}
```javascript
const oauthToken = "...";
const import = true;
const session = await client.authenticateFacebook(oauthToken, true, "mycustomusername", import);
console.log("Successfully authenticated:", session);
```
{{< / code >}}

{{< code type="client" >}}
```csharp
const string oauthToken = "...";
var session = await client.AuthenticateFacebookAsync(oauthToken);
System.Console.WriteLine("New user: {0}, {1}", session.Created, session);
```
{{< / code >}}

{{< code type="client" >}}
```cpp
auto loginFailedCallback = [](const NError& error)
{
};

auto loginSucceededCallback = [](NSessionPtr session)
{
    cout << "Authenticated successfully. User ID: " << session->getUserId() << endl;
};

std::string oauthToken = "...";
bool importFriends = true;
client->authenticateFacebook(oauthToken, "mycustomusername", true, importFriends, {}, loginSucceededCallback, loginFailedCallback);
```
{{< / code >}}

{{< code type="client" >}}
```java
String oauthToken = "...";
Session session = client.authenticateFacebook(oauthToken).get();
System.out.format("Session %s", session.getAuthToken());
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
var oauth_token = "..."
var session : NakamaSession = yield(client.authenticate_facebook_async(oauth_token), "completed")

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
```
{{< / code >}}

{{< code type="client" framework="defold">}}
```lua
-- Use the official Defold Facebook integration (www.defold.com/extension-facebook)
local permissions = { "public_profile" }
-- login using read permissions
-- there is no need to specify a publishing audience when requesting read permissions
facebook.login_with_permissions(permissions, facebook.AUDIENCE_NONE, function(self, data)
  local result = client.authenticate_facebook(facebook.access_token(), nil, true, "mycustomusername")

  if not result.token then
    print("Unable to login")
    return
  end
  -- store the token and use it when communicating with the server
  client.set_bearer_token(result.token)
end)
```
{{< / code >}}

#### Facebook Instant

`FBInstant.initializeAsync()`을(를) 사용하여 Nakama용 FB Instant App Secret을 [구성했고](../../getting-started/configuration/#facebook-instant-game) Facebook Instant Games SDK 사용을 초기화했는지 확인합니다.

{{< missing type="client" lang="csharp" />}}
{{< missing type="client" lang="gdscript" />}}
{{< missing type="client" lang="java" />}}
{{< missing type="client" lang="cpp" />}}
{{< missing type="client" lang="bash" />}}

{{< code type="client" >}}
```javascript
const result = await FBInstant.player.getSignedPlayerInfoAsync();
var session = await client.authenticateFacebookInstantGame(result.getSignature());
console.info("Successfully authenticated: %o", session);
```
{{< / code >}}

{{< code type="client" framework="defold">}}
```lua
-- Use the official Defold Facebook Instant Games integration (www.defold.com/extension-fbinstant)
fbinstant.get_signed_player_info("developer payload", function(self, signature)
  local result = client.authenticate_facebook_instant_game(signature, nil, true, "mycustomusername")

  if not result.token then
    print("Unable to login")
    return
  end
  -- store the token and use it when communicating with the server
  client.set_bearer_token(result.token)
end)
```
{{< / code >}}

#### Google

등록 및 로그인을 위해 Facebook과 비슷하게 Google의 클라이언트 SDK 중 하나를 사용해야 합니다.

계정을 만들 때 사용자 지정 사용자 이름을 선택할 수 있습니다. 이렇게 하려면 `username`을(를) 사용자 지정 이름으로 설정합니다. 사용자 계정을 암시적으로 만들지 않고 `create`만 인증하려면 false로 설정합니다.

{{< code type="client" >}}
```bash
curl "http://127.0.0.1:7350/v2/account/authenticate/google?create=true&username=mycustomusername" \
  --user 'defaultkey:' \
  --data '{"token":"valid-oauth-token"}'
```
{{< / code >}}

{{< code type="client" >}}
```shell
POST /v2/account/authenticate/google?create=true&username=mycustomusername
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Basic base64(ServerKey:)
{
  "token": "...",
}
```
{{< / code >}}

{{< code type="client" >}}
```javascript
const playerIdToken = "...";
const create = true;
const session = await client.authenticateGoogle(oauthToken, create, "mycustomusername");
console.info("Successfully authenticated: %o", session);
```
{{< / code >}}

{{< code type="client" >}}
```csharp
const string playerIdToken = "...";
var session = await client.AuthenticateGoogleAsync(playerIdToken);
System.Console.WriteLine("New user: {0}, {1}", session.Created, session);
```
{{< / code >}}

{{< code type="client" >}}
```cpp
auto successCallback = [](NSessionPtr session)
{
    std::cout << "Authenticated successfully. User ID: " << session->getUserId() << std::endl;
};

auto errorCallback = [](const NError& error)
{
};

string oauthToken = "...";
client->authenticateGoogle(oauthToken, "mycustomusername", true, {}, successCallback, errorCallback);
```
{{< / code >}}

{{< code type="client" >}}
```java
String playerIdToken = "...";
Session session = client.authenticateGoogle(oauthToken).get();
System.out.format("Session %s", session.getAuthToken());
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
var oauth_token = "..."
var session : NakamaSession = yield(client.authenticate_google_async(oauth_token), "completed")

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
```
{{< / code >}}

{{< code type="client" framework="defold">}}
```lua
local result = client.authenticate_google(oauth_token, nil, true, "mycustomusername")

if not result.token then
  print("Unable to login")
end

-- store the token and use it when communicating with the server
client.set_bearer_token(result.token)
```
{{< / code >}}

#### 게임 센터

Apple 장치에는 게임 센터를 통한 사용자 상호 작용없이 수행할 수있는 기본 제공 인증이 있습니다. 레지스터 또는 로그인 프로세스는 Apple 서비스 작동 방식으로 인해 약간 복잡합니다.

계정을 만들 때 사용자 지정 사용자 이름을 선택할 수 있습니다. 이렇게 하려면 `username`을(를) 사용자 지정 이름으로 설정합니다. 사용자 계정을 암시적으로 만들지 않고 `create`만 인증하려면 false로 설정합니다.

{{< missing type="client" lang="javascript" />}}
{{< missing type="client" lang="java" />}}

{{< code type="client" >}}
```bash
curl "http://127.0.0.1:7350/v2/account/authenticate/gamecenter?create=true&username=mycustomusername" \
  --user 'defaultkey:' \
  --data '{"player_id":"...", "bundle_id":"...", "timestamp_seconds":0, "salt":"...", "public_key_url":"..."}'
```
{{< / code >}}

{{< code type="client" >}}
```shell
POST /v2/account/authenticate/gamecenter?create=true&username=mycustomusername
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Basic base64(ServerKey:)
{
  "player_id": "...",
  "bundle_id": "...",
  "timestamp_seconds": 0,
  "salt": "...",
  "signature": "...",
  "public_key_url": "..."
}
```
{{< / code >}}

{{< code type="client" >}}
```csharp
var bundleId = "...";
var playerId = "...";
var publicKeyUrl = "...";
var salt = "...";
var signature = "...";
var timestamp = "...";
var session = await client.AuthenticateGameCenterAsync(bundleId, playerId,
    publicKeyUrl, salt, signature, timestamp);
System.Console.WriteLine("New user: {0}, {1}", session.Created, session);
```
{{< / code >}}

{{< code type="client" >}}
```cpp
auto successCallback = [](NSessionPtr session)
{
    std::cout << "Authenticated successfully. User ID: " << session->getUserId() << std::endl;
};

auto errorCallback = [](const NError& error)
{
};

std::string playerId = "...";
std::string    bundleId = "...";
NTimestamp timestampSeconds = "...";
std::string salt = "...";
std::string signature = "...";
std::string publicKeyUrl = "...";

client->authenticateGameCenter(playerId, bundleId, timestampSeconds, salt, signature, publicKeyUrl, "mycustomusername", true, {}, successCallback, errorCallback);
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
var bundle_id = "..."
var player_id = "..."
var public_key_url = "..."
var salt = "..."
var signature = "..."
var timestamp = "..."
var session : NakamaSession = yield(client.authenticate_game_center_async(bundle_id, player_id, public_key_url, salt, signature, timestamp), "completed")

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
```
{{< / code >}}

{{< code type="client" framework="defold">}}
```lua
-- Use https://defold.com/assets/gamekit/
local bundle_id = "..."
local player_id = "..."
local public_key_url = "..."
local salt = "..."
local signature = "..."
local timestamp_seconds = 0
local result = client.authenticate_game_center(bundle_id, player_id, public_key_url, salt, signature, timestamp_seconds, nil, true, "mycustomusername")

if not result.token then
  print("Unable to login")
end

-- store the token and use it when communicating with the server
client.set_bearer_token(result.token)
```
{{< / code >}}

#### Steam

Steam의 경우 사용자를 등록하려면 먼저 서버를 구성해야 합니다. 서버에 필요한 설정에 대한 [구성](../../getting-started/configuration/#steam) 섹션을 참조하십시오.

계정을 만들 때 사용자 지정 사용자 이름을 선택할 수 있습니다. 이렇게 하려면 `username`을(를) 사용자 지정 이름으로 설정합니다. 사용자 계정을 암시적으로 만들지 않고 `create`만 인증하려면 false로 설정합니다.

인증할 때 선택적으로 Steam Friends를 Nakama의 [친구 그래프](../friends/)로 가져올 수 있습니다. 이렇게 하려면 `import`을(를) True로 설정합니다.

{{< missing type="client" lang="javascript" />}}

{{< code type="client" >}}
```bash
curl "http://127.0.0.1:7350/v2/account/authenticate/steam?create=true&username=mycustomusername&import=true" \
  --user 'defaultkey:' \
  --data '{"token":"valid-steam-token"}'
```
{{< / code >}}

{{< code type="client" >}}
```shell
POST /v2/account/authenticate/steam?create=true&username=mycustomusername&import=true
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Basic base64(ServerKey:)
{
  "token": "...",
}
```
{{< / code >}}

{{< code type="client" >}}
```javascript
const token = "...";
const create = true;
const username = "...";
const sync = true;
const session = await client.authenticateSteam(token, create, username, sync);
console.info("Successfully authenticated: %o", session);
```
{{< / code >}}

{{< code type="client" >}}
```csharp
const string token = "...";
const bool importFriends = true;
var session = await client.AuthenticateSteamAsync(token, importFriends);
System.Console.WriteLine("New user: {0}, {1}", session.Created, session);
```
{{< / code >}}

{{< code type="client" >}}
```cpp
auto successCallback = [](NSessionPtr session)
{
    std::cout << "Authenticated successfully. User ID: " << session->getUserId() << std::endl;
};

auto errorCallback = [](const NError& error)
{
};

string token = "...";
string username = "mycustomusername";
bool create = true;
bool importFriends = true;
client->authenticateSteam(token, username, create, importFriends, {}, successCallback, errorCallback);
```
{{< / code >}}

{{< code type="client" >}}
```java
String token = "...";
Bool importFriends = true;
Session session = client.authenticateSteam(token, importFriends).get();
System.out.format("Session %s", session.getAuthToken());
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
var steam_token = "..."
var import_friends = true
var session : NakamaSession = yield(client.authenticate_steam_async(steam_token, import_friends), "completed")

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
```
{{< / code >}}

{{< code type="client" framework="defold">}}
```lua
-- Use https://defold.com/assets/steamworks/
local result = client.authenticate_steam(steam_token, nil, true, "mycustomusername")

if not result.token then
  print("Unable to login")
end

-- store the token and use it when communicating with the server
client.set_bearer_token(result.token)
```
{{< / code >}}

### 사용자 지정

사용자 지정 식별자는 장치 식별자와 비슷한 방식으로 사용하여 사용자를 로그인하거나 등록할 수 있습니다. 이 옵션은 사용하려는 외부 또는 사용자 지정 사용자 ID 서비스가 있는 경우 사용해야 합니다. 예를 들어 EA의 Origin 서비스는 자체 사용자 ID가 있는 계정을 처리합니다.

사용자 지정 식별자는 대시가 있는 영숫자 문자를 포함해야 하며 6 ~ 128 바이트여야 합니다.

계정을 만들 때 사용자 지정 사용자 이름을 선택할 수 있습니다. 이렇게 하려면 `username`을(를) 사용자 지정 이름으로 설정합니다. 사용자 계정을 암시적으로 만들지 않고 `create`만 인증하려면 false로 설정합니다.

{{< code type="client" >}}
```bash
curl "http://127.0.0.1:7350/v2/account/authenticate/custom?create=true&username=mycustomusername" \
  --user 'defaultkey:' \
  --data '{"id":"some-custom-id"}'
```
{{< / code >}}

{{< code type="client" >}}
```shell
POST /v2/account/authenticate/custom?create=true&username=mycustomusername
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Basic base64(ServerKey:)
{
  "id": "some-custom-id",
}
```
{{< / code >}}

{{< code type="client" >}}
```javascript
const customId = "some-custom-id";
const create = true;
const session = await client.authenticateCustom(customId, create, "mycustomusername");
console.info("Successfully authenticated:", session);
```
{{< / code >}}

{{< code type="client" >}}
```csharp
const string customId = "some-custom-id";
var session = await client.AuthenticateCustomAsync(customId);
System.Console.WriteLine("New user: {0}, {1}", session.Created, session);
```
{{< / code >}}

{{< code type="client" >}}
```cpp
auto successCallback = [](NSessionPtr session)
{
    std::cout << "Authenticated successfully. User ID: " << session->getUserId() << std::endl;
};

auto errorCallback = [](const NError& error)
{
};

string id = "some-custom-id";
string username = "mycustomusername";
bool create = true;
client->authenticateCustom(id, username, create, {}, successCallback, errorCallback);
```
{{< / code >}}

{{< code type="client" >}}
```java
String customId = "some-custom-id";
Session session = client.authenticateCustom(customId).get();
System.out.format("Session %s", session.getAuthToken());
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
var custom_id = "some-custom-id"
var session : NakamaSession = yield(client.authenticate_custom_async(custom_id), "completed")

if session.is_exception():
    print("An error occurred: %s" % session)
    return

print("Successfully authenticated: %s" % session)
```
{{< / code >}}

{{< code type="client" framework="defold">}}
```lua
local result = client.authenticate_custom(custom_id, nil, true, "mycustomusername")

if not result.token then
  print("Unable to login")
end

-- store the token and use it when communicating with the server
client.set_bearer_token(result.token)
```
{{< / code >}}

## 세션

인증 호출이 성공하면 서버는 [세션](/docs/concepts/session/) 객체로 응답합니다. 세션 객체에는 최소한 다음이 포함되어 있습니다:

- 사용자 ID
- 사용자 이름
- 토큰에 캐시된 변수 세트
- 생성 시간
- 만료 시간

클라이언트가 세션 객체를 얻으면 [멀티 플레이어](../multiplayer/relayed/), [알림](../notifications/) 및 [상태 업데이트](../status/), [스트림 데이터 전달](../../server-framework/streams/) 또는 [실시간 채팅](../chat/)과 같은 Nakama의 실시간 기능을 활용할 수 있습니다.

{{< code type="client" >}}
```javascript
var socket = client.createSocket();
session = await socket.connect(session);
console.info("Socket connected.");
```
{{< / code >}}

{{< code type="client" >}}
```csharp
var socket = Socket.From(client);
await socket.ConnectAsync(session);
System.Console.WriteLine("Socket connected.");
```
{{< / code >}}

{{< code type="client" >}}
```cpp
int port = 7350; // different port to the main API port
bool createStatus = true; // if the server should show the user as online to others.
// define real-time client in your class as NRtClientPtr rtClient;
rtClient = client->createRtClient(port);
// define listener in your class as NRtDefaultClientListener listener;
listener.setConnectCallback([]()
{
    cout << "Socket connected." << endl;
});

rtClient->setListener(&listener);
rtClient->connect(session, createStatus);
```
{{< / code >}}

{{< code type="client" >}}
```java
SocketClient socket = client.createSocket();
socket.connect(session, new AbstractSocketListener() {}).get();
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
# Make this a node variable, or it will disconnect when the function that creates it returns.
onready var socket := Nakama.create_socket_from(client)

func _ready():
    var connected : NakamaAsyncResult = yield(socket.connect_async(session), "completed")

    if connected.is_exception():
        print("An error occurred: %s" % connected)
        return

    print("Socket connected.")
```
{{< / code >}}

{{< code type="client" framework="defold">}}
```lua
local socket = client.create_socket()
local ok, err = socket.connect()

if not ok then
  print("Unable to connect: ", err)
end
```
{{< / code >}}

## 연결 또는 연결 해제

하나 이상의 다른 로그인 옵션을 현재 사용자에게 연결할 수 있습니다. 이렇게 하면 각 사용자와 여러 로그인을 쉽게 지원하고 여러 장치에서 사용자를 쉽게 식별할 수 있습니다.

다른 사용자 계정에 아직 사용되지 않은 장치 ID, 사용자 지정 ID 및 소셜 공급자 ID만 연결할 수 있습니다.

{{< code type="client" >}}
```bash
curl "http://127.0.0.1:7350/v2/account/link/custom" \
  --header 'Authorization: Bearer $session' \
  --data '{"id":"some-custom-id"}'
```
{{< / code >}}

{{< code type="client" >}}
```shell
POST /v2/account/link/custom
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Bearer <session token>
{
  "id":"some-custom-id"
}
```
{{< / code >}}

{{< code type="client" >}}
```javascript
const customId = "some-custom-id";
const success = await client.linkCustom(session, customId);
console.log("Successfully linked custom ID to current user.");
```
{{< / code >}}

{{< code type="client" >}}
```csharp
const string customId = "some-custom-id";
await client.LinkCustomAsync(session, customId);
System.Console.WriteLine("Id '{0}' linked for user '{1}'", customId, session.UserId);
```
{{< / code >}}

{{< code type="client" >}}
```cpp
auto linkFailedCallback = [](const NError& error)
{
};

auto linkSucceededCallback = []()
{
    cout << "Linked successfully" << endl;
};

std::string customid = "some-custom-id";

client->linkCustom(customid, linkSucceededCallback, linkFailedCallback);
```
{{< / code >}}

{{< code type="client" >}}
```java
String customId = "some-custom-id";
client.linkCustom(session, customId).get();
System.out.format("Id %s linked for user %s", customId, session.getUserId());
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
var custom_id = "some-custom-id"
var linked : NakamaAsyncResult = yield(client.link_custom_async(session, custom_id), "completed")

if linked.is_exception():
    print("An error occurred: %s" % linked)
    return

print("Id '%s' linked for user '%s'" % [custom_id, session.user_id])
```
{{< / code >}}

{{< code type="client" framework="defold">}}
```lua
local result = client.link_custom(custom_id)

if result.error then
  print("An error occurred:", result.error)
end
```
{{< / code >}}

현재 사용자의 연결된 로그인 옵션을 해제할 수 있습니다.

{{< code type="client" >}}
```bash
curl "http://127.0.0.1:7350/v2/account/unlink/custom" \
  --header 'Authorization: Bearer $session' \
  --data '{"id":"some-custom-id"}'
```
{{< / code >}}

{{< code type="client" >}}
```shell
POST /v2/account/unlink/custom
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Bearer <session token>
{
  "id":"some-custom-id"
}
```
{{< / code >}}

{{< code type="client" >}}
```javascript
const customId = "some-custom-id";
const success = await client.unlinkCustom(session, customId);
console.info("Successfully unlinked custom ID from the current user.");
```
{{< / code >}}

{{< code type="client" >}}
```csharp
const string customId = "some-custom-id";
await client.UnlinkCustomAsync(session, customId);
System.Console.WriteLine("Id '{0}' unlinked for user '{1}'", customId, session.UserId);
```
{{< / code >}}

{{< code type="client" >}}
```cpp
auto unlinkFailedCallback = [](const NError& error)
{
};

auto unlinkSucceededCallback = []()
{
    cout << "Successfully unlinked custom ID from the current user." << endl;
};

std::string customid = "some-custom-id";

client->unlinkCustom(customid, unlinkSucceededCallback, unlinkFailedCallback);
```
{{< / code >}}

{{< code type="client" >}}
```java
String customId = "some-custom-id";
client.unlinkCustom(session, customId).get();
System.out.format("Id %s unlinked for user %s", customId, session.getUserId());
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
var custom_id = "some-custom-id"
var unlinked : NakamaAsyncResult = yield(client.unlink_custom_async(session, custom_id), "completed")

if unlinked.is_exception():
    print("An error occurred: %s" % unlinked)
    return

print("Id '%s' unlinked for user '%s'" % [custom_id, session.user_id])
```
{{< / code >}}

{{< code type="client" framework="defold">}}
```lua
local result = client.unlink_custom(custom_id)

if result.error then
  print("An error occurred:", result.error)
end
```
{{< / code >}}

다양한 계정 옵션을 연결하거나 해제할 수 있습니다.

| 연결        | 설명                                                                         |
|-------------|-------------------------------------------------------------------------------------|
| Apple       | Apple 계정.                                                                   |
| 사용자 지정      | 다른 ID 서비스의 사용자 지정 식별자.                                  |
| 장치      | 사용자에게 속하는 장치의 고유 식별자.                         |
| 이메일       | 사용자가 설정한 이메일 및 암호.                                              |
| Facebook    | Facebook 소셜 계정. 연결 할 때 Facebook 친구를 선택적으로 가져올 수 있습니다. |
| 게임 센터 | Apple 게임 센터 서비스의 계정.                                        |
| Google      | Google 계정.                                                                   |
| Steam       | Steam 네트워크의 계정.                                                  |
