> ## 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.

# Sharing Credentials

> Share existing OAuth client credentials between Junction BYOO and your own systems when providers allow only one redirect URI.

## Audience

This guide is dedicated to Junction customers looking to share the usage of their OAuth Client Credentials
between Junction [Bring Your Own OAuth](/wearables/connecting-providers/bring-your-own-oauth/overview) and their
existing production systems.

This guide is not applicable if you:

* do not have existing OAuth Client Credentials; or
* can configure your OAuth Client Credentials to point exclusively at Junction.

## Background

Many providers use OAuth 2.0, in which each partner entity is registered as a confidential application.
Each application is issued one set of OAuth client credentials (client ID + secret).

As a Cross-Site Request Forgery (CSRF) mitigation, they also typically require every application to pre-register
a Redirect URI. The `/authorize` flow would then validate inbound requests against the Redirect URI on record.

## Challenge

Most providers allow **only one** Redirect URI registration per OAuth application.

This means your OAuth application cannot simultaneously support both your own existing OAuth callback endpoint, as well as
[Junction Link](/wearables/connecting-providers/introduction) OAuth callback endpoint.

## Recommended Approach

To support this credential sharing use case, Junction recommends that you:

1. Continue to point your OAuth application at your existing OAuth callback endpoint;

2. Extend your endpoint to [detect and redirect](#details) callbacks from Junction Link originated OAuth requests to the
   [Junction Link OAuth callback endpoint](#junction-oauth-callback-endpoint-url).

```mermaid theme={null}
sequenceDiagram
    participant Junction Link
    participant Your API
    participant BYOO Provider
    actor User Agent
    autonumber
    Junction Link-->>User Agent: OAuth 2.0 Authorization Request URL
    User Agent->>BYOO Provider: Navigate to URL (1)
    BYOO Provider-->>User Agent: Prompt
    User Agent-->>BYOO Provider: Approve or Deny
    BYOO Provider->>Your API: Redirect
    Your API->>Junction Link: Redirect
```

### Details

<Steps>
  <Step title="Keep your current OAuth application settings">
    The Redirect URI in your OAuth application settings should continue to point at your
    existing OAuth callback endpoint.
  </Step>

  <Step title="Extend your existing OAuth callback endpoint with Junction Link awareness">
    Your OAuth callback endpoints can rely on the `state` query parameter to differentiate the request
    origin, i.e., whether it is from Junction or from your own production systems.

    OAuth requests originating from Junction would have the **Junction Link Token** as the `state` query parameter.
    Junction Link Token is a JSON Web Token (JWT), so you can use the *unverified claims* of the JWT as a discriminator.

    When you detect a valid Junction Link Token, perform a `307 Temporary Redirect`
    to the [Junction OAuth callback endpoint](#junction-oauth-callback-endpoint-url) and pass on *all* the URL query parameters.

    The exact JWT structure of the Junction Link Token is as follows:

    <AccordionGroup>
      <Accordion title="Encoding" defaultOpen>
        A JSON Web Token (JWT).

        <Warning>
          You need not verify the signature of this JWT.

          To prevent Cross-Site Request Forgery attacks, you must still check that the `aud` claim matches the
          expected [Junction Link API Base URL](#junction-link-api-base-url).
        </Warning>
      </Accordion>

      <Accordion title="Claim payload schema" defaultOpen>
        | Key       | Value                      |
        | --------- | -------------------------- |
        | `aud`     | Junction Link API Base URL |
        | `sub`     | Junction Link Session ID   |
        | `team_id` | Junction Team ID           |
        | `user_id` | Junction User ID           |
      </Accordion>

      <Accordion title="Junction Link API Base URL" defaultOpen>
        | Environment   | Base URL                                     |
        | ------------- | -------------------------------------------- |
        | Production US | `https://api.tryvital.io/v2/link`            |
        | Production EU | `https://api.eu.tryvital.io/v2/link`         |
        | Sandbox US    | `https://api.sandbox.tryvital.io/v2/link`    |
        | Sandbox EU    | `https://api.sandbox.eu.tryvital.io/v2/link` |
      </Accordion>

      <Accordion title="Junction OAuth callback endpoint URL" defaultOpen>
        | Environment   | Base URL                                                        |
        | ------------- | --------------------------------------------------------------- |
        | Production US | `https://api.tryvital.io/v2/link/connect/{PROVIDER}`            |
        | Production EU | `https://api.eu.tryvital.io/v2/link/connect/{PROVIDER}`         |
        | Sandbox US    | `https://api.sandbox.tryvital.io/v2/link/connect/{PROVIDER}`    |
        | Sandbox EU    | `https://api.sandbox.eu.tryvital.io/v2/link/connect/{PROVIDER}` |
      </Accordion>

      <Accordion title="Example" defaultOpen>
        ```python Python (FastAPI) theme={null}
        import fastapi
        from urllib.parse import urlencode

        VITAL_LINK_BASE_URL = "https://api.tryvital.io/v2/link"

        @router.get("/oauth_callback/fitbit")
        def handle_oauth_callback(
            request: fastapi.Request,
            state: Annotated[str, fastapi.Query()],
            ...,
        ) -> fastapi.Response:
            state_string = base64.b64decode(state)

            # Test if this is a JWT.
            # If so, try to extract the unverified claim payload, and see if this is
            # a Junction Link JWT.
            if (
                state_string.startswith('{"')
                and (state_parts := state_string.split(".", maxsplit=3))
                and len(state_parts) == 3
                and (unverified_claims := json.loads(state_parts[1]))
                and unverified_claims.get("aud") == VITAL_LINK_BASE_URL
            ):
                query = urlencode(request.query_params)

                return fastapi.RedirectResponse(f"{VITAL_LINK_BASE_URL}/connect/fitbit?{query}")


            # Not a Junction Link JWT. Fallback to existing logic
            return process_oauth_callback(...)

        ```
      </Accordion>
    </AccordionGroup>
  </Step>

  <Step title="Register your OAuth callback endpoint with Junction">
    When you set your OAuth Client Credentials through the [Set Team Custom Credentials](/api-reference/org-management/team-custom-credentials/upsert-team-custom-credentials)
    endpoint, you must specify a Redirect URI override that points at your OAuth callback endpoint.

    When a Redirect URI override is present, Junction uses the override value you provided to initiate the OAuth authorization flow.
  </Step>
</Steps>
