# IDP Routing Strategies
When using external identity providers, you need to decide how to route users to the correct IDP. Medplum supports two primary strategies:

## 1. App-based Routing (Client ID)
In this model, the Identity Provider is determined by the application the user is logging into. This is configured on the `ClientApplication` resource.

- **How it works:** You configure specific IDP details (Authorize URL, Client ID, etc.) on your Medplum `ClientApplication`.
- **Use Case:** You have a "Patient App" that uses Auth0 for all users, and a separate "Provider App" that uses Okta.
- **Setup:** Follow the [Setup](/content/docs/auth/external-identity-providers#setup/index.html) instructions below to configure the IDP on your `ClientApplication`.

## 2. Domain-based Routing (Email Domain)
In this model, the Identity Provider is determined by the user's email address. This is configured using [Domain Configuration](/content/docs/auth/domain-level-identity-providers/index.html).

- **How it works:** You map an email domain (e.g., `hospital.com`) to an IDP. When a user enters their email, Medplum routes them to that IDP.
- **Use Case:** You have enterprise customers who want their employees to log in with their corporate credentials (SSO), regardless of which app they are using.
- **Setup:** See the [Domain-level Identity Providers](/content/docs/auth/domain-level-identity-providers/index.html) guide.

# Auth flow
When an end user authenticates with your client-side web application, we will use the following authentication flow:

# Example repo
Medplum provides a minimal example application which demonstrates using Auth0 as an external identity provider. The example is approximately 100 lines of TypeScript code, and can be used as a starting point for any standard OAuth2/OpenID identity provider.

> [https://github.com/medplum/medplum-client-external-idp-demo](https://github.com/medplum/medplum-client-external-idp-demo)

# Setup
Setup your external authentication provider (Auth0, AWS Cognito, Okta, etc). Use " [https://api.medplum.com/auth/external](https://api.medplum.com/auth/external)" as the "redirect URI" (also known as the "callback URL" in some systems).

Also make sure that your provider accepts the `profile` OIDC scope.

Note the following details:
- Authorize URL
- Token URL
- UserInfo URL
- Client ID
- Client secret

Setup your Medplum account:
- [Register for a Medplum account](/content/docs/tutorials/register/index.html)
- Create a `ClientApplication`
- Set the "Redirect URI" to " [http://localhost:8000/](http://localhost:8000/)"
- Add an external identity provider with the details from above

# Self-hosted server-scoped identity providers
The `IdentityProvider` resource is server-scoped. On self-hosted deployments, creating or editing server-scoped identity provider configuration requires super admin context. Project administrators can configure identity provider settings on project `ClientApplication` resources, but they cannot create server-scoped `IdentityProvider` resources unless they are operating as super admin.

# Start the flow
The [MedplumClient](/content/docs/sdk/core.medplumclient) TypeScript class provides a [`signInWithExternalAuth`](/content/docs/sdk/core.medplumclient.signinwithexternalauth) convenience method:

```ts
// The login button handler
// The user can click this button to initiate the OAuth flow

$('login').addEventListener('click', () =>
  medplum.signInWithExternalAuth(EXTERNAL_AUTHORIZE_URL, EXTERNAL_CLIENT_ID, EXTERNAL_REDIRECT_URI, {
    projectId: MEDPLUM_PROJECT_ID,
    clientId: MEDPLUM_CLIENT_ID,
    redirectUri: WEB_APP_REDIRECT_URI,
  })
);
```

# Handle the code
When the external identity provider flow redirects back to your web application, it will include a `code` query parameter. This code can be exchanged for a Medplum access token.

The [MedplumClient](/content/docs/sdk/core.medplumclient) TypeScript class provides a [`processCode`](/content/docs/sdk/core.medplumclient.processcode) convenience method:

```ts
// The code check
// If the current URL includes a "code" query string param, then we can exchange it for a token

const code = new URLSearchParams(window.location.search).get('code');

if (code) {
  // Process the code
  // On success, remove the query string parameters
  medplum
    .processCode(code)
    .then(() => (window.location.href = window.location.href.split('?')[0]))
    .catch(console.error);
}
```

After the code is processed, the Medplum access token will be stored in the browser's local storage. The `MedplumClient` will automatically use the access token for all subsequent API calls.

# FAQ
### AWS Cognito
- (If using the Cognito's hosted UI) Set the "redirect uri" by navigating to: Amazon Cognito > User Pools > [Your pool] > [Your App Client] > Edit Hosted UI > Allowed callback URLs
- By default, Cognito does not include the `profile` scope. You can add this navigating to: Amazon Cognito > User Pools > [Your pool] > [Your App Client] > Edit Hosted UI > OpenID Connect Scopes
- To disable PKCE for Cognito login, do the following:

```ts
medplum.signInWithExternalAuth(
  EXTERNAL_AUTHORIZE_URL,
  EXTERNAL_CLIENT_ID,
  EXTERNAL_REDIRECT_URI,
  {
    projectId: MEDPLUM_PROJECT_ID,
    clientId: MEDPLUM_CLIENT_ID,
    redirectUri: WEB_APP_REDIRECT_URI,
  },
  false,
);
```

- In the Medplum App, navigate to your [ClientApplication](https://app.medplum.com/ClientApplication) > Edit and set "PKCE Optional" to `true`

- [IDP Routing Strategies](/content/docs/auth/external-identity-providers#idp-routing-strategies/index.html)
  - [1. App-based Routing (Client ID)](/content/docs/auth/external-identity-providers#1-app-based-routing-client-id/index.html)
  - [2. Domain-based Routing (Email Domain)](/content/docs/auth/external-identity-providers#2-domain-based-routing-email-domain/index.html)
- [Auth flow](/content/docs/auth/external-identity-providers#auth-flow/index.html)
- [Example repo](/content/docs/auth/external-identity-providers#example-repo/index.html)
- [Setup](/content/docs/auth/external-identity-providers#setup/index.html)
- [Start the flow](/content/docs/auth/external-identity-providers#start-the-flow/index.html)
- [Handle the code](/content/docs/auth/external-identity-providers#handle-the-code/index.html)
- [FAQ](/content/docs/auth/external-identity-providers#faq/index.html)
  - [AWS Cognito](/content/docs/auth/external-identity-providers#aws-cognito/index.html)
