> ## Documentation Index
> Fetch the complete documentation index at: https://docs.junction.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Mobile SDK Authentication

> Authenticate Junction Mobile SDKs using Sign-In Tokens that give each app installation scoped API access as an individual user.

## Junction Sign-In Token

In the *Junction Sign-In Token* scheme, each mobile app installation signs in with Junction Mobile SDK
as an individual user in your Team. The app installation would be granted only Junction API access
scoped to that specific user.

Instead of hardcoding a [Junction Team API Key](#junction-team-api-keys), your app would request your own backend to generate
a **Junction Sign-In Token** for the user, through your own API authentication and authorization systems.

In this model, your Junction Team API Keys are kept strictly as a server-side secret.

<CardGroup cols={2}>
  <Card title="Persistence" icon="hand-wave">
    The signed-in user is persistent across app relaunch and device reboots.
  </Card>

  <Card title="Access Scope" icon="lock">
    Only user-level resources of the signed-in user can be accessed.
  </Card>
</CardGroup>

### Overview

<AccordionGroup>
  <Accordion title="Sign in once" icon="right-to-bracket" iconType="sharp-solid" defaultOpen>
    In typical circumstances, within each app installation, you would sign in your authenticated user only once
    with the Junction Mobile SDK. You would do so as part of your app's user lifecycle.

    There are some known circumstances where you would have to sign in the user again:

    * You have signed out your user in response to your app's user lifecycle changes; or
    * The Junction SDK sign-in state is out of sync with your app's user lifecycle; or
    * The SDK automatically signed out, because it had detected the deletion of the Junction User.

    <Note>
      It is unnecessary to request and sign in with the Junction Sign-In Token every time your app launches.
    </Note>
  </Accordion>

  <Accordion title="Integrating into your app's user lifecycle" icon="arrows-spin" iconType="sharp-solid" defaultOpen>
    You should sign in and sign out of the Junction Mobile SDK as an integral part of your app's user lifecycle:

    1. When the user signs in to your app, you would request the Junction Sign-In Token from your backend, and then sign in with the Junction Mobile SDK.

    2. When the user signs out from your app, you would also sign out from the Junction Mobile SDK.

    Junction Mobile SDK persists the signed-in Junction User — as well as any settings and sync state — across app relaunches and device reboots.
  </Accordion>

  <Accordion title="A recommendation to perform regular reconciliation" icon="merge" iconType="sharp-solid" defaultOpen>
    We recommend regularly reconciling the state of the Junction Mobile SDK and your app's user lifecycle. This is because:

    1. The SDK sign-in process involves remote API calls, which can fail due to Internet connectivity;

    2. Unknown edge cases in your integration of Junction Core SDK into your app's user lifecycle may result in
       the state being out of sync; and

    3. If you are integrating Junction Mobile SDK into an existing production app, this reconciliation can serve
       as a one-off migration for app installations upgrading from an older version of your app.

    You can achieve this through the [Core SDK](/wearables/sdks/vital-core#core-sdk-status) API in three steps:

    1. Query the [Core SDK](/wearables/sdks/vital-core#core-sdk-status) Status and the Current User ID;
    2. Compare these against your app's user state; and
    3. Only if a discrepancy is detected, perform a Junction SDK sign-in or sign-out in accordance with the discrepancy.

    You would typically schedule this as an asynchronous task that spawns when your application process launches.

    <Warning>
      Do not sign in and sign out every time your application process launches.
    </Warning>
  </Accordion>

  <Accordion title="Technical details" icon="circle-info" iconType="sharp-solid" defaultOpen>
    **Junction Sign-In Token** is a short-lived bearer token issued for a specific Junction User.
    Junction Mobile SDK uses it to sign in with Junction's Identity Provider as the Junction User represented by the
    token.

    Each app installation can only have one active signed-in Junction User.

    Internally, the Junction Mobile SDK:

    1. **exchanges** the short-lived Junction Sign-In Token for a permanent sign-in, which is in the form of
       an OAuth 2.0 access token and an OAuth 2.0 refresh token.
    2. discards the Junction Sign-In Token upon a successful exchange.
    3. stores these token secrets securely in the device persistent storage.
    4. calls the Junction API using the OAuth 2.0 access token.
    5. transparently manages the OAuth 2.0 refresh token flow to keep the access token fresh and valid.

    This is why the documentation emphasizes the "sign in once" expectation. The SDK does not rely on
    the Junction Sign-In Token for day-to-day operation and API calls. It only needs this artifact once upfront
    to exchange for the token secrets it needs.
  </Accordion>
</AccordionGroup>

### Case Study: A typical Backend - Mobile App flow

<Steps>
  <Step title="Your app -> Your identity provider">
    ```mermaid theme={null}
    sequenceDiagram
        participant Your App
        actor Your Identity Provider
        autonumber
        Your App->>Your Identity Provider: User authentication
        Your Identity Provider-->>Your App: Token Secret for authenticating to your Backend API
    ```

    Your end user signs in with your Identity Provider — a separate IdP, or your own API acting as one — through password authentication,
    Social Login, Single Sign-On (SSO) or any other authentication methods.
  </Step>

  <Step title="Your app -> Your backend API">
    ```mermaid theme={null}
    sequenceDiagram
        participant Your App
        actor Your Backend
        autonumber
        Your App->>Your Backend: Request the user profile
        Your Backend-->>Your App: User profile
        Your App->>Your Backend: Request a Junction Sign-In Token for the user
    ```

    Once your user has successfully authenticated, your app is issued with token secrets for accessing your backend API.
    Your app stores these token secrets securely.

    It then makes some API requests to your backend API, in order to gather all information required to set up your app
    into an authenticated state.

    Among these API requests, one would be requesting your backend API to issue a Junction Sign-In Token for your authenticated user.
  </Step>

  <Step title="Your backend service <-> Junction API">
    ```mermaid theme={null}
    sequenceDiagram
        actor Your Backend
        actor Junction API
        autonumber
        Your Backend->>Junction API: Token Request via API Key
        Junction API-->>Your Backend: Issued a Junction Sign-In Token
    ```

    Your backend API receives and validates the token issuance request. Once validated, your backend service:

    * Looks up the Junction User associated with this authenticated user;

    * If one does not yet exist, call the [Create User](/api-reference/user/create-user) endpoint to create a Junction User; and

    * Call the [Create Sign-In Token](/api-reference/user/create-sign-in-token) endpoint to obtain a Junction Sign-In Token for
      this Junction User.

    <Note>
      Only this step would use a [Junction Team API Key](/api-details/junction-api#authentication). Because this step happens in your
      backend service, this enables you to keep the Junction Team API Key strictly as a server-side secret.
    </Note>

    ```bash theme={null}
    curl --request POST
      --url '{{BASE_URL}}/v2/user/{{USER_ID}}/sign_in_token'
      --header 'X-Vital-API-Key: <YOUR-API-KEY>'
    ```

    Your backend API then responds to your app with the obtained Junction Sign-In Token:

    ```json theme={null}
    {
      "user_id": "e209947b-323e-4108-8e18-1518b80da0bd",
      "sign_in_token": "XYZ=="
    }
    ```
  </Step>

  <Step title="Your backend API -> Your app">
    ```mermaid theme={null}
    sequenceDiagram
        participant Your App
        participant Junction Mobile SDK
        actor Your Backend
        autonumber
        Your Backend-->>Your App: The Junction Sign-In Token
        Your App->>Junction Mobile SDK: Sign in with Junction Sign-In Token
    ```

    Your app receives a response from your backend API, which includes the Junction Sign-In Token for the authenticated
    user.

    Your app then calls the Junction Mobile SDK `signIn` method with the Junction Sign-In Token:

    <CodeGroup>
      ```swift Native iOS theme={null}
      import VitalCore

      let response: MyAPIResponse = // ....

      do {
        try await VitalClient.signIn(withRawToken: response.signInToken)

        print("Signed in with Junction successfully")
      } catch let error {
        print("Error signing in with Junction", error)
      }
      ```

      ```kotlin Native Android theme={null}
      import io.tryvital.client.VitalClient
      import android.content.Context
      import android.util.Log

      val response: MyAPIResponse
      val applicationContext: Context

      try {
        VitalClient.signIn(applicationContext, response.signInToken)

        Log.i("vital_sdk", "Signed in with Junction successfully")
      } catch (e: Throwable) {
        Log.e("vital_sdk", "Error signing in with Junction", e)
      }
      ```

      ```typescript React Native theme={null}
      import { VitalCore } from "@tryvital/vital-core-react-native";

      const response: MyAPIResponse

      try {
        await VitalCore.signIn(response.signInToken)

        console.log("Signed in with Junction successfully")
      } catch (error) {
        console.error("Error signing in with Junction", error)
      }
      ```

      ```dart Flutter theme={null}
      import 'package:vital_core/vital_core.dart' as vital_core;

      MyAPIResponse response;

      try {
        await vital_core.signIn(response.signInToken)

        Fimber.i("Signed in with Junction successfully")
      } catch (error) {
        Fimber.e("Error signing in with Junction", error)
      }
      ```
    </CodeGroup>

    <br />

    <Warning>
      `signIn()` throws an error when you have already signed in with the Junction SDK.

      You can [inspect the Core SDK status](/wearables/sdks/vital-core#core-sdk-status) at any time for troubleshooting. You can
      also rely on the Core SDK status to reconcile differences between your own user session state and Junction SDK sign-in.
    </Warning>
  </Step>

  <Step title="Voilà!">
    The Junction Mobile SDK is now signed-in with the Junction User associated with your authenticated user.
    You can now proceed to use all the Junction SDK features.
  </Step>
</Steps>

## Junction Team API Keys

<Warning>
  API Key is **discouraged** for production mobile apps, since it would be distributed as cleartext.
  API Key support is intended only for customer early evaluation in Sandbox.

  Use [Junction Sign-In Token](#junction-sign-in-token) whenever possible.
</Warning>

Junction Mobile SDK can be configured to authenticate using API Key alongside a target user ID.

<CodeGroup>
  ```swift Native iOS theme={null}
  import VitalCore

  VitalClient.configure(
    apiKey: "sk_us_...",
    environment: .sandbox(.us)
  )
  VitalClient.setUserId(UUID(uuidString: "ccd6f98d-3a2a-433b-a114-8fe064f301ed")!)
  ```

  ```kotlin Native Android theme={null}
  import io.tryvital.client.VitalClient
  import android.content.Context

  val applicationContext: Context

  VitalClient.configure(
    applicationContext,
    Region.US,
    Environment.Sandbox,
    "sk_us_..."
  )
  VitalClient.setUserId(applicationContext, "ccd6f98d-3a2a-433b-a114-8fe064f301ed")
  ```

  ```typescript React Native theme={null}
  import { VitalCore } from "@tryvital/vital-core-react-native";

  await VitalCore.configure(
      "sk_us_...",
      "sandbox",
      "us",
      true,
  );
  await VitalCore.setUserId("ccd6f98d-3a2a-433b-a114-8fe064f301ed");
  ```

  ```dart Flutter theme={null}
  import 'package:vital_core/vital_core.dart' as vital_core;

  await vital_core.configure(
    "sk_us_...",
    vital_core.Environment.sandbox,
    vital_core.Region.us
  );
  await vital_core.setUserId("ccd6f98d-3a2a-433b-a114-8fe064f301ed");
  ```
</CodeGroup>

<br />

<Info>
  When running on iOS, the SDK must be **explicitly** configured before other SDK methods can be invoked.

  Alternatively, follow the [Apple HealthKit guide](/wearables/guides/apple-healthkit#setting-up-apple-healthkit-background-delivery)
  to enable SDK Automatic Configuration during app launch. This auto-configures the SDK using the last known configuration you supplied — including but
  not limited to the API Key, the environment and the target User ID. Not only is this a prerequisite to enable HealthKit Background Delivery, this
  allows you also to only call `configure(...)` and `setUserId(...)` once to "sign-in" the user persistently when using the Junction Team API Key scheme.
</Info>

## Sign Out

Regardless of the authentication scheme you used, you can sign out with the Junction SDK using `signOut()`.
This erases any persistent user session and configuration stored by the Junction Core and Health SDKs.

<CodeGroup>
  ```swift Native iOS theme={null}
  import VitalCore

  await VitalClient.shared.signOut()
  ```

  ```kotlin Native Android theme={null}
  import io.tryvital.client.VitalClient
  import android.content.Context

  val applicationContext: Context

  VitalClient.getOrCreate(applicationContext).signOut()
  ```

  ```typescript React Native theme={null}
  import { VitalCore } from "@tryvital/vital-core-react-native";

  await VitalCore.signOut();
  ```

  ```dart Flutter theme={null}
  import 'package:vital_core/vital_core.dart' as vital_core;

  await vital_core.signOut();
  ```
</CodeGroup>

## Migrate from Junction Team API Keys to Junction Sign-In Tokens

<Warning>
  Always use [Junction Sign-In Token](#junction-sign-in-token) for your production mobile apps.
</Warning>

An existing app installation signed-in with Junction Team API Key + User ID can be seamlessly migrated to
use Junction Sign-In Tokens.

It is as simple as performing a one-off migration logic during app launch:

<Steps>
  <Step title="Condition to migrate">
    Check whether the Junction SDK status includes `useApiKey` (i.e., the user is signed in using Junction Team API Key).
  </Step>

  <Step title="Obtain a Junction Sign-In Token">
    Similar to the new user sign-in flow, your app needs to obtain a Junction Sign-In Token through your backend service.
  </Step>

  <Step title="Sign-in with the token">
    Your app can simply sign-in with the Junction Sign-In Token.

    Note that it is **unnecessary to reset** the SDK beforehand — the SDK `signIn` method would automatically migrate, as
    long as the supplied Sign-In Token is compatible with the existing API Key sign-in (i.e., having the same Junction user ID,
    same Junction environment, and same Junction region).
  </Step>
</Steps>

<CodeGroup>
  ```swift Native iOS theme={null}
  import VitalCore

  if VitalClient.status.contains(.useApiKey) {
    do {
      let response = await callBackend(...)
      try await VitalClient.signIn(withToken: response.signInToken)
      print("Signed in with Junction successfully")
    } catch let error {
      print("Error signing in with Junction", error)
    }
  }
  ```

  ```kotlin Native Android theme={null}
  import io.tryvital.client.VitalClient
  import android.content.Context
  import android.util.Log

  val applicationContext: Context

  VitalClient.getOrCreate(applicationContext)

  if (VitalClient.Status.useApiKey in VitalClient.status) {
    try {
        val response = callBackend(...)
        VitalClient.signIn(applicationContext, response.signInToken)

        Log.i("vital_sdk", "Signed in with Junction successfully")
    } catch (e: Throwable) {
        Log.e("vital_sdk", "Error signing in with Junction", e)
    }
  }
  ```

  ```typescript React Native theme={null}
  import { VitalCore } from "@tryvital/vital-core-react-native";

  const status = await VitalCore.status();

  if (status.includes("useApiKey")) {
    try {
        const response = await callBackend(...);
        await VitalCore.signIn(response.signInToken);

        console.log("Signed in with Junction successfully");
    } catch (error) {
        console.error("Error signing in with Junction", error);
    }
  }
  ```

  ```dart Flutter theme={null}
  import 'package:vital_core/vital_core.dart' as vital_core;

  Set<vital_core.ClientStatus> status = await vital_core.clientStatus();

  if (status.contains(vital_core.ClientStatus.useApiKey)) {
    try {
        MyAPIResponse response = await callBackend(...);
        await vital_core.signIn(response.signInToken)

        Fimber.i("Signed in with Junction successfully")
    } catch (error) {
        Fimber.e("Error signing in with Junction", error)
    }
  }
  ```
</CodeGroup>
