# Authentication Providers

**URL:** https://heroiclabs.com/docs/nakama/concepts/authentication/authentication-providers/
**Summary:** Register an authentication provider for any external identity service, such as Epic, PlayStation Network or Discord, and it becomes a way to sign in that Nakama handles like the built-in methods. An account can hold one identity per registered provider.
**Keywords:** authentication, provider, custom, link, unlink, epic, playstation, discord, runtime
**Categories:** nakama, concepts

---


# Authentication providers

Authentication providers let you plug any identity system into Nakama as a first-class sign-in method. In addition to the social providers Nakama supports natively, you can connect a third-party identity provider or your own. You can also import the player's friends from that platform into Nakama's friend graph.

## The provider module

A provider module is server runtime code that sits between Nakama and an external identity platform. Nakama provides the client API endpoints, keeps track of the providers you register, and links identities to accounts. The module implementation is custom per platform.

You can [write your own module](#creating-a-provider) with the server runtime API. Our goal is to have a range of provider modules for social platforms published as open-source plugins.

## How a provider identity sits on a Nakama account

A provider identity is a first-class identifier. It can create or sign into a Nakama account using a third-party platform's user ID. A Nakama account holds one identity per registered provider alongside its device IDs, email and social IDs, as described in [how accounts and identifiers relate](../#how-accounts-and-identifiers-relate).

### Provider identity

An authentication provider for an external platform is identified by the combination of provider name  and provider user ID. For example:
```text
  provider name:    epic
  provider user ID: 123456789
```
- **The provider name**: The name can contain letters, numbers, underscores, and hyphens (`[a-zA-Z0-9_-]`), up to 128 bytes. Nakama lowercases the provider name at registration and when handling authenticate and link requests, so `Epic`, `EPIC`, and `epic` all resolve to the same provider. The lowercase form is stored with the provider identity and shown in the Nakama Console.
- **The provider user ID**: There is no required format for the provider ID. It can be whatever immutable account ID the external platform uses. The only requirement is that the ID cannot contain whitespace or control characters. The maximum allowed length is 128 bytes.

{{< note important >}}
When a provider identity is used to create a new Nakama account, Nakama checks whether the provider user ID can be parsed as a UUID. If it can, that value becomes the Nakama user ID. Otherwise, Nakama generates a random UUID.

This design is intentional: when using a single central identity solution, Nakama account IDs will match those in your external identity system.
{{</note >}}

As with the built-in social IDs, these same two rules apply to a provider identity:

- An account can hold only one identity per provider. For example, a second *epic* identity cannot be added to an account that already has one.
- A provider identity can belong to only one account. For instance, the same *epic* ID cannot sign a player into two accounts.

## Authentication flow

The client sends Nakama a provider name and an opaque payload. Nakama passes the payload to your provider module, which verifies the credential with the external platform and returns the player's stable provider account ID.

{{< diagram
src="/images/pages/nakama/concepts/authentication/auth_plugin_flow.svg"
desc="A left to right flow with arrows running in both directions between four boxes: game client, Nakama, provider module, and external identity platform. The game client sends a provider name of platform_x and a payload that is an opaque JSON object to Nakama. Nakama passes the payload to the provider module, which sends the credential to the external identity platform. The platform returns the platform account ID to the provider module, the provider module returns the provider account ID to Nakama, and Nakama returns a session token to the game client."
>}}

The sequence is:
1. The client sends a provider name and payload to Nakama. The payload is opaque JSON. See [Define your payload](#2-define-your-payload)
2. Nakama passes the payload to your provider module.
3. Your provider verifies the credential. The provider communicates with the external platform and verifies that the credential belongs to a valid account.
4. Your provider returns the platform account ID.
5. Nakama maps the provider identity to a Nakama account.  If the identity is new and `create` is `true`, Nakama creates an account. Otherwise, Nakama returns the existing account.
6. If your provider implements friends import, Nakama calls it and your provider returns the player's friends list, which Nakama adds to the new or existing account's [friend graph](../../friends/).
7. The client receives a Nakama session.

### Importing friends

When the external platform exposes the player's social graph, your provider can import those friends into Nakama during the same authenticate or link request. If you implement the `GetFriends` runtime function, Nakama makes a separate call to it right after `Authenticate` returns, passing it the authenticate result.

{{< diagram
src="/images/pages/nakama/concepts/authentication/getfriends_flow.svg"
max-width="80%"
desc="A left to right flow with arrows running in both directions between three boxes: Nakama, provider module, and external identity platform. After Authenticate succeeds, Nakama calls GetFriends on the provider module, which requests the player's friends from the external identity platform. The platform returns the friend list to the provider module, and the provider module returns the provider friend IDs to Nakama."
>}}

After your provider returns the player's friends from the external platform, Nakama matches them against existing Nakama accounts that use the same provider identity, adding each match to the player's [friend graph](../../friends/). Friends without a Nakama account are skipped. For implementation details, see [Import friends from the provider](#4-import-friends-from-the-provider).

## Creating a provider

To create a provider, implement a function that verifies the player's credential with the external platform and returns the player's provider user ID. Then register the function with Nakama using the server runtime API.

Here are the steps:
### 1. Choose the provider name

- Pick the name clients will send, such as `epic`. See [provider identity](#provider-identity) for the naming rules and how casing is handled.
- Once you use a name for an identity system, you can't change it. Renaming a provider after launch breaks the link between that provider and the accounts that use it. 

### 2. Define your payload

- The payload is JSON. The client sends a JSON object, Nakama parses it, and passes it to your function without inspecting the contents.
- The shape is whatever your provider needs: a single access token, an authorization code, a signed ticket, or several values together.

### 3. Write the authenticate function

This is the function Nakama calls for every authenticate and link request for your provider. It receives the payload from the client, verifies the credential, and returns the player's provider user ID.

In Go, a provider satisfies the following interface:

```go
type AuthenticateProvider interface {
    Authenticate(ctx context.Context, logger Logger, db *sql.DB, nk NakamaModule, payload map[string]any) (AuthenticateProviderResult, error)
    GetFriends(ctx context.Context, logger Logger, db *sql.DB, nk NakamaModule, payload map[string]any, result AuthenticateProviderResult) ([]string, bool, error)
}
```

`Authenticate` verifies the credential. `GetFriends` imports the player's friends from the external platform and is covered in [step 4](#4-import-friends-from-the-provider). If you don't need the friends import functionality, you can implement `GetFriends` to return `nil`.

#### What to return

Your function returns the provider user ID, and optionally a username, session variables, and metadata.

```go
type DefaultAuthenticateProviderResult struct {
    ProviderUserID string            `json:"provider_user_id"`
    Username       string            `json:"username,omitempty"`
    Vars           map[string]string `json:"vars,omitempty"`
    Metadata       map[string]any    `json:"metadata,omitempty"`
}
```

- **Provider user ID**, required. The value Nakama stores and looks up on every subsequent sign-in. See [provider identity](#provider-identity) for the rules it must satisfy.
- **Username**, optional. Used only when creating an account.
- **Session variables**, optional. String values only, bundled into the session token.
- **Metadata**, optional. This is used as a bridge from `Authenticate` to `GetFriends`. `GetFriends` is the runtime function that gets called after authentication succeeds. Often some kind of token information is needed to perform a friends request; this metadata field can keep that token so friends request can read it. See [step 4](#4-import-friends-from-the-provider).

Here's an example in Go:
```go
type EpicProvider struct{}

func (p *EpicProvider) Authenticate(ctx context.Context, logger runtime.Logger,
    db *sql.DB, nk runtime.NakamaModule, payload map[string]any) (runtime.AuthenticateProviderResult, error) {

    accessToken, _ := payload["access_token"].(string)
    if accessToken == "" {
        return nil, runtime.NewError("payload is missing access_token", 3)
    }

    // Verify the token with Epic and read back the account it belongs to.
    // Replace this with a real call to the platform's API.
    account, err := verifyWithEpic(ctx, accessToken)
    if err != nil {
        return nil, runtime.NewError("token rejected by provider", 16)
    }

    return &runtime.DefaultAuthenticateProviderResult{
        ProviderUserID: account.ID,
        Vars:           map[string]string{"platform": "epic"},
        // Set it here so GetFriends can read it.
        Metadata:       map[string]any{"access_token": accessToken},
    }, nil
}
```

### 4. Import friends from the provider

During authentication and linking, if the external platform exposes the player's friends, your provider can import them into Nakama's [friend graph](../../friends/).

This is done by implement `GetFriends` runtime function. Here's the shape:
```go
type AuthenticateProvider interface {
    Authenticate(ctx context.Context, logger Logger, db *sql.DB, nk NakamaModule, payload map[string]any) (AuthenticateProviderResult, error)
    GetFriends(ctx context.Context, logger Logger, db *sql.DB, nk NakamaModule, payload map[string]any, result AuthenticateProviderResult) ([]string, bool, error)
}
```

Nakama calls `GetFriends` right after `Authenticate` and passes the result you returned. This is where the `Metadata` field mentioned in step 3 comes in. `Authenticate` can hand data to `GetFriends` through the result's `Metadata` field, such as an access token it obtained while verifying the credential.

In addition to the friends' provider user IDs, your function call can do a reset of the player's friends. Set the boolean in the return value to `true` to replace the existing friends, `false` to add to them.

```go
func (p *EpicProvider) GetFriends(ctx context.Context, logger runtime.Logger,
    db *sql.DB, nk runtime.NakamaModule, payload map[string]any,
    result runtime.AuthenticateProviderResult) ([]string, bool, error) {

    // Read the token Authenticate stored in the result metadata.
    accessToken, _ := result.GetMetadata()["access_token"].(string)

    friendIDs, err := listEpicFriends(ctx, accessToken)
    if err != nil {
        return nil, false, err
    }

    return friendIDs, false, nil
}
```

### 5. Register the provider

Register your provider during runtime initialization. In Go, use `RegisterAuthenticateProvider` to register the provider with Nakama.

```go
RegisterAuthenticateProvider(name string, provider AuthenticateProvider) error
```

The provider argument is the type whose authenticate function you wrote in [step 3](#3-write-the-authenticate-function).

Here's an example:
```go
func InitModule(ctx context.Context, logger runtime.Logger, db *sql.DB,
    nk runtime.NakamaModule, initializer runtime.Initializer) error {
    return initializer.RegisterAuthenticateProvider("epic", &EpicProvider{})
}
```

## Linking and unlinking

As with Nakama's native social sign-in methods, you can link a provider identity to an existing Nakama account. Use authenticate to find or create an account from a provider identity, and link to add that identity to an account the player is already signed in to.

There are two ways to use a provider identity:

* **Authenticate first, link later.** The player signs in with a device ID, email, or social ID, then links the provider identity to their existing account.
* **Authenticate with the provider first.** A provider identity can be used to create a Nakama account just like any other identity. You can then link other sign-in methods to the account.

To use the link functionality, you must register the provider's Authenticate runtime function first. Nakama passes the client payload to the registered function to verify the credential and obtain the provider user ID.

Unlinking removes the provider identity from the account. The last remaining identifier cannot be unlinked, so the player always has a way to sign in.

## Hooks

Just like the built-in authentication methods, you can run custom logic around each provider operation with before and after hooks. See [Hooks](../../../server-framework/introduction/hooks/).

