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

# OAuth Action

> The OAuth action restricts access to only authorized users by enforcing OAuth through an identity provider of your choice.

export const YouTubeEmbed = ({className, title, videoId, ...props}) => {
  return <div className={`relative aspect-video mb-3 ${className}`} {...props}>
      <iframe src={`https://www.youtube.com/embed/${videoId}`} allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen className="absolute inset-0 w-full h-full" title={title} />
    </div>;
};

export const ConfigChildren = ({children}) => {
  return <Accordion title="Show Child Properties">
      {children}
    </Accordion>;
};

export const ConfigField = ({title, type, cel = false, defaultValue = false, required = false, children}) => {
  const id = `config-${title.replace(/\.|\s|\*/g, "_")}`;
  return <div className="field pt-2.5 pb-5 my-2.5 border-gray-50 dark:border-gray-800/50 border-b" style={{
    scrollMarginTop: '120px'
  }} id={id}>
      <div className="flex font-mono group/param-head param-head break-all relative">
        <div className="flex-1 flex content-start py-0.5 mr-5">
          <div className="flex items-center flex-wrap gap-2">
            <div class="absolute -top-1.5">
              <a href={`#${id}`} className="-ml-10 flex items-center opacity-0 border-0 group-hover/param-head:opacity-100 py-2 [.expandable-content_&]:-ml-[2.1rem]" aria-label="Navigate to header">
                ​<div className="w-6 h-6 rounded-md flex items-center justify-center shadow-sm text-gray-400 dark:text-white/50 dark:bg-background-dark dark:brightness-[1.35] dark:ring-1 dark:hover::rightness-150 bg-white ring-1 ring-gray-400/30 dark:ring-gray-700/25 hover:ring-gray-400/60 dark:hover:ring-white/20">
                  <svg xmlns="http://www.w3.org/2000/svg" fill="gray" height="12px" viewBox="0 0 576 512"><path d="M0 256C0 167.6 71.6 96 160 96h72c13.3 0 24 10.7 24 24s-10.7 24-24 24H160C98.1 144 48 194.1 48 256s50.1 112 112 112h72c13.3 0 24 10.7 24 24s-10.7 24-24 24H160C71.6 416 0 344.4 0 256zm576 0c0 88.4-71.6 160-160 160H344c-13.3 0-24-10.7-24-24s10.7-24 24-24h72c61.9 0 112-50.1 112-112s-50.1-112-112-112H344c-13.3 0-24-10.7-24-24s10.7-24 24-24h72c88.4 0 160 71.6 160 160zM184 232H392c13.3 0 24 10.7 24 24s-10.7 24-24 24H184c-13.3 0-24-10.7-24-24s10.7-24 24-24z"></path></svg>
                </div>
              </a>
            </div>
            <div className="font-semibold text-primary dark:text-primary-light overflow-wrap-anywhere">{title}</div>
            <div className="inline items-center gap-2 text-xs font-medium [&_div]:inline [&_div]:mr-2 [&_div]:leading-5 [&_a]:inline [&_a]:mr-2 [&_a]:leading-5">
              {type && <div className="flex items-center px-2 py-0.5 rounded-md bg-gray-100/50 dark:bg-white/5 break-all">
                <span className="text-gray-600 dark:text-gray-200 !font-medium">{type}</span>
              </div>}
              {defaultValue && <div className="flex items-center px-2 py-0.5 rounded-md bg-gray-100/50 dark:bg-white/5 break-all">
                  <span class="text-gray-400 dark:text-gray-500">default:</span>
                  <span className="text-gray-600 dark:text-gray-200 !font-medium">{defaultValue}</span>
                </div>}
              {required && <div className="px-2 py-0.5 rounded-md bg-red-100/50 dark:bg-red-400/10 whitespace-nowrap">
                <span className="text-red-600 dark:text-red-300 !font-medium">Required</span>
              </div>}
              {cel && <a className="px-2 py-0.5 rounded-md !border-none bg-blue-100/50 dark:bg-blue-400/10 whitespace-nowrap" href="/traffic-policy/concepts/cel-interpolation">
                <span className="text-blue-600 dark:text-blue-300 !font-medium">Supports CEL</span>
              </a>}
            </div>
          </div>
        </div>
      </div>
      <div className="mt-4 prose-sm prose-gray dark:prose-invert [&_.prose>p:first-child]:mt-0 [&_.prose>p:last-child]:mb-0">
        {children}
      </div>
    </div>;
};

<Note>
  This page relates to requiring OAuth for visitors to access your endpoints.
  To configure OAuth and SSO providers for signing into the ngrok dashboard, see [the dashboard SSO documentation](/iam/sso).
</Note>

The OAuth Traffic Policy action restricts access to your endpoints to only authorized users by enforcing OAuth through an identity provider of your choice.

<YouTubeEmbed videoId="yGf_OdknZkM" title="OAuth Traffic Policy action" />

## Configuration reference

The [Traffic Policy](/traffic-policy/) configuration reference for this action.

### Supported phases

`on_http_request`

### Type

`oauth`

### Configuration fields

<ConfigField title="provider" type="string" required={true}>
  The name of the *OAuth* identity provider to be used for authentication.
</ConfigField>

<ConfigField title="auth_id" type="string" required={false}>
  Unique authentication identifier for this provider.
  Used to scope the session cookie and to target this provider in login and logout paths.
  See [Special paths](#special-paths).
</ConfigField>

<ConfigField title="client_id" type="string" required={false} cel={true}>
  Your OAuth app's client ID.

  <Note>
    Leave this empty if you want to use ngrok's managed application.
  </Note>
</ConfigField>

<ConfigField title="client_secret" type="string" required={false} cel={true}>
  Your OAuth app's client secret.

  <Note>
    Leave this empty if you want to use a managed application.
  </Note>
</ConfigField>

<ConfigField title="scopes" type="array of strings" required={false}>
  A list of additional scopes to request when users authenticate with the identity provider.
</ConfigField>

<ConfigField title="authz_url_params" type="map of string to string" required={false}>
  A map of additional URL parameters to apply to the authorization endpoint URL.
</ConfigField>

<ConfigField title="max_session_duration" type="duration" required={false}>
  Defines the maximum lifetime of a session regardless of activity.
</ConfigField>

<ConfigField title="idle_session_timeout" type="duration" required={false}>
  Defines the period of inactivity after which a user's session is automatically ended, requiring re-authentication.
</ConfigField>

<ConfigField title="userinfo_refresh_interval" type="duration" required={false}>
  How often should ngrok refresh data about the authenticated user from the identity provider.
</ConfigField>

<ConfigField title="allow_cors_preflight" type="boolean" required={false} defaultValue={false}>
  Allow CORS preflight requests to bypass authentication checks.
  Enable this if the endpoint needs to be accessible via CORS.
</ConfigField>

<ConfigField title="auth_cookie_domain" type="string" required={false}>
  Sets the allowed domain for the auth cookie.
</ConfigField>

### Special paths

#### Logging users in

To start an OAuth authentication flow explicitly—for example, from a "Log in" button or link—redirect users to `/ngrok/login`.
After a successful authentication, ngrok redirects the user to `/`.

To send the user to a specific path after login, include the `redirect_path` parameter:

```
/ngrok/login?redirect_path=/dashboard
```

If you've configured `auth_id` to identify this provider, include it in the URL:

```
/ngrok/login?auth_id=my-provider&redirect_path=/dashboard
```

If the IdP supports it, ngrok instructs it to force re-authentication—users must re-enter their credentials even if they already have an active IdP session.

#### Logging users out

To end a user's session—for example, from a "Log out" button or link—redirect users to `/ngrok/logout`.
This clears the ngrok session cookie.

If you've configured `auth_id`, include it in the URL to target the correct provider:

```
/ngrok/logout?auth_id=my-provider
```

<Note>
  When using the Google OAuth 2.0/OIDC provider in Chrome with a [managed profile](https://support.google.com/chrome/a/answer/188446), `/ngrok/logout` only clears the ngrok session cookie; it does not end the Google/IdP session maintained by the browser.
  Users may be silently re-authenticated on the next request.
  To fully sign out, sign out of Chrome or Google (or use a non-managed profile or Incognito) in addition to calling `/ngrok/logout`.
</Note>

### Events

When this action is enabled, it populates the following fields in the [`http_request_complete.v0`](/obs/events/reference/#http-request-complete) event:

* `oauth.app_client_id`
* `oauth.decision`
* `oauth.user.id`
* `oauth.user.name`

### Supported providers

ngrok currently supports the following OAuth providers (see the Integration Guides for more details).
In some instances, ngrok has a [managed application](#managed-applications) that allows you to configure OAuth without setting up your own application in your provider.
This is useful for testing and development, but when you move into production, use your own custom application in your specific provider.

| Provider  | Provider Identifier | Managed App Available | Integration Guide                                    |
| --------- | ------------------- | --------------------- | ---------------------------------------------------- |
| Amazon    | `amazon`            | no                    | [Documentation](/integrations/oauth/oauth/)          |
| Facebook  | `facebook`          | no                    | [Documentation](/integrations/oauth/facebook-oauth)  |
| GitHub    | `github`            | yes                   | [Documentation](/integrations/oauth/github-oauth)    |
| GitLab    | `gitlab`            | yes                   | [Documentation](/integrations/oauth/gitlab-oauth)    |
| Google    | `google`            | yes                   | [Documentation](/integrations/oauth/google-oauth)    |
| LinkedIn  | `linkedin`          | yes                   | [Documentation](/integrations/oauth/linkedin-oauth)  |
| Microsoft | `microsoft`         | yes                   | [Documentation](/integrations/oauth/microsoft-oauth) |
| Twitch    | `twitch`            | yes                   | [Documentation](/integrations/oauth/twitch-oauth)    |

### Required scopes

This is a list of the minimum required scopes for each provider.
You can use this when configuring your identity provider.
These are not required when using the ngrok managed applications.

| Provider  | Scopes                                                                                               |
| --------- | ---------------------------------------------------------------------------------------------------- |
| Amazon    | `profile`                                                                                            |
| Facebook  | `email`                                                                                              |
| Github    | `read:org`, `read:user`                                                                              |
| Gitlab    | `email`, `openid`, `profile`                                                                         |
| Google    | `https://www.googleapis.com/auth/userinfo.email`, `https://www.googleapis.com/auth/userinfo.profile` |
| LinkedIn  | `r_emailaddress`, `r_liteprofile`                                                                    |
| Microsoft | `User.Read`                                                                                          |
| Twitch    | `user:read:email`                                                                                    |

## Try it out

See the list of [supported providers](#supported-providers) for step-by-step integration guides.

## Behavior

### Callback URL

When you create your own OAuth app, you must specify a callback (or redirect) URL to the OAuth provider.
When using ngrok's OAuth action, the callback URL is always:

```
https://idp.ngrok.com/oauth2/callback
```

### Authentication

When an unauthenticated request is made to an OAuth-protected endpoint, it returns a redirect response that begins an authentication flow with the configured identity provider.
The original URI path is saved so that users can be redirected to it if they successfully authenticate.

**If the user fails to authenticate with the identity provider**, ngrok will display an error describing the failure returned by the identity provider and prompt them to try logging in again.

**If the user successfully authenticates with the identity provider**, ngrok will take the following actions:

* Sets a [session cookie](#cookies) to avoid repeating the authentication flow again.
* Redirects the user to the original URI path they were attempting to access before the authentication flow began.
  If no such URI path was captured, they are redirected to `/`.
* Continue processing the rest of the Traffic Policy actions.

### Continuous authorization

When an authenticated user makes a request, ngrok will sometimes refresh a user's data from the identity provider (email, name, etc.) and re-evaluate authorization constraints.
This refresh is executed as a back channel request to the identity provider; it is transparent to the user and they do not go through a re-authentication flow.

The following circumstances trigger refresh and authorization re-evaluation:

* On a periodic interval defined by the [`userinfo_refresh_interval`](/traffic-policy/actions/oauth/#configuration-fields) parameter.
* If you update the OAuth configuration of the endpoint either in the agent or through the dashboard.
* If you update the OAuth configuration of the endpoint.

If a previously authenticated user becomes unauthorized because their identity provider information changed or because the OAuth action configuration changed, they are presented an error and are prompted to try logging in again.

### Managed applications

Managed applications allow you to use ngrok's OAuth action without setting up your own OAuth apps with the identity providers.
More practically, this means you can use the OAuth action without configuring a client id and client secret.

Managed applications are great for getting started but they have some limitations.

* They are [only available for some identity providers](#supported-providers).
* You may not pass custom scopes when using a managed application.
* The [upstream headers](/gateway/http/#upstream-headers) `ngrok-auth-oauth-access-token` and `ngrok-auth-oauth-refresh-token` are not sent to your application.

### Traffic identities

ngrok's [Traffic Identities](/traffic-policy/identities/) feature can be used to observe
all of the authenticated user activity across your account in the ngrok
dashboard or via API. Whenever a user authenticates or accesses an endpoint
with a configured OIDC action, their Traffic Identity record is created or updated.

You may also use Traffic Identities to remotely log a user out by [revoking a
session](/traffic-policy/identities/#revoke-sessions).

### Cookies

This action sets two cookies in its operation.
Cookie values are opaque to the upstream service and must not be modified.

| Cookie    | Description                             |
| --------- | --------------------------------------- |
| `session` | Used to track an authenticated user.    |
| `nonce`   | Used to secure the authentication flow. |

### Non-terminating action

This is a **Non-terminating action**. It does not return a response, and will allow Traffic Policy processing to continue to the next Action in the chain. All **Cloud Endpoint** Traffic Policies must end with a terminating action. This requirement does not apply to **Agent Endpoints**.

## Examples

### Using a managed provider

The following [Traffic Policy](/traffic-policy/) configuration will provide your app with a Google authentication step.

<CodeGroup>
  ```yaml policy.yml theme={null}
  on_http_request:
    - actions:
        - type: oauth
          config:
            provider: google
  ```

  ```json policy.json theme={null}
  {
    "on_http_request": [
      {
        "actions": [
          {
            "type": "oauth",
            "config": {
              "provider": "google"
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

You can replace the `provider` value with any of the [supported providers](/traffic-policy/actions/oauth/#supported-providers) that have a managed app available.

### Restricting access to certain users

See [this authentication example](/traffic-policy/examples/add-authentication/#conditional-access-using-oauth-variables) to learn how to restrict access based on OAuth result variables.

### Using a Custom Provider

If you need more control than what a managed provider can offord you then you
can bring your own provider.

#### Google Example

<CodeGroup>
  ```yaml policy.yml theme={null}
  on_http_request:
    - actions:
        - type: oauth
          config:
            provider: google
            client_id: '{your oauth client id}'
            client_secret: '{your oauth client secret}'
            scopes:
              - https://www.googleapis.com/auth/userinfo.profile
              - https://www.googleapis.com/auth/userinfo.email
  ```

  ```json policy.json theme={null}
  {
    "on_http_request": [
      {
        "actions": [
          {
            "type": "oauth",
            "config": {
              "provider": "google",
              "client_id": "{your oauth client id}",
              "client_secret": "{your oauth client secret}",
              "scopes": [
                "https://www.googleapis.com/auth/userinfo.profile",
                "https://www.googleapis.com/auth/userinfo.email"
              ]
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

#### GitHub Example

<CodeGroup>
  ```yaml policy.yml theme={null}
  on_http_request:
    - actions:
        - type: oauth
          config:
            provider: github
            client_id: '{your app''s oauth client id}'
            client_secret: '{your app''s oauth client secret}'
            scopes:
              - read:user
              - read:org
  ```

  ```json policy.json theme={null}
  {
    "on_http_request": [
      {
        "actions": [
          {
            "type": "oauth",
            "config": {
              "provider": "github",
              "client_id": "{your app's oauth client id}",
              "client_secret": "{your app's oauth client secret}",
              "scopes": [
                "read:user",
                "read:org"
              ]
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

#### GitLab Example

<CodeGroup>
  ```yaml policy.yml theme={null}
  on_http_request:
    - actions:
        - type: oauth
          config:
            provider: gitlab
            client_id: '{your app''s oauth client id}'
            client_secret: '{your app''s oauth client secret}'
            scopes:
              - openid
              - profile
              - email
  ```

  ```json policy.json theme={null}
  {
    "on_http_request": [
      {
        "actions": [
          {
            "type": "oauth",
            "config": {
              "provider": "gitlab",
              "client_id": "{your app's oauth client id}",
              "client_secret": "{your app's oauth client secret}",
              "scopes": [
                "openid",
                "profile",
                "email"
              ]
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

#### LinkedIn Example

<CodeGroup>
  ```yaml policy.yml theme={null}
  on_http_request:
    - actions:
        - type: oauth
          config:
            provider: linkedin
            client_id: '{your app''s oauth client id}'
            client_secret: '{your app''s oauth client secret}'
            scopes:
              - r_emailaddress
              - r_liteprofile
  ```

  ```json policy.json theme={null}
  {
    "on_http_request": [
      {
        "actions": [
          {
            "type": "oauth",
            "config": {
              "provider": "linkedin",
              "client_id": "{your app's oauth client id}",
              "client_secret": "{your app's oauth client secret}",
              "scopes": [
                "r_emailaddress",
                "r_liteprofile"
              ]
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

#### Microsoft Example

<CodeGroup>
  ```yaml policy.yml theme={null}
  on_http_request:
    - actions:
        - type: oauth
          config:
            provider: microsoft
            client_id: '{your app''s oauth client id}'
            client_secret: '{your app''s oauth client secret}'
            scopes:
              - openid
              - email
              - profile
  ```

  ```json policy.json theme={null}
  {
    "on_http_request": [
      {
        "actions": [
          {
            "type": "oauth",
            "config": {
              "provider": "microsoft",
              "client_id": "{your app's oauth client id}",
              "client_secret": "{your app's oauth client secret}",
              "scopes": [
                "openid",
                "email",
                "profile"
              ]
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

#### Twitch Example

<CodeGroup>
  ```yaml policy.yml theme={null}
  on_http_request:
    - actions:
        - type: oauth
          config:
            provider: twitch
            client_id: '{your app''s oauth client id}'
            client_secret: '{your app''s oauth client secret}'
            scopes:
              - user:read:email
              - openid
  ```

  ```json policy.json theme={null}
  {
    "on_http_request": [
      {
        "actions": [
          {
            "type": "oauth",
            "config": {
              "provider": "twitch",
              "client_id": "{your app's oauth client id}",
              "client_secret": "{your app's oauth client secret}",
              "scopes": [
                "user:read:email",
                "openid"
              ]
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

#### Amazon Example

<CodeGroup>
  ```yaml policy.yml theme={null}
  on_http_request:
    - actions:
        - type: oauth
          config:
            provider: amazon
            client_id: '{your app''s oauth client id}'
            client_secret: '{your app''s oauth client secret}'
            scopes:
              - profile
  ```

  ```json policy.json  theme={null}
  {
    "on_http_request": [
      {
        "actions": [
          {
            "type": "oauth",
            "config": {
              "provider": "amazon",
              "client_id": "{your app's oauth client id}",
              "client_secret": "{your app's oauth client secret}",
              "scopes": [
                "profile"
              ]
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

#### Facebook Example

<CodeGroup>
  ```yaml policy.yml theme={null}
  on_http_request:
    - actions:
        - type: oauth
          config:
            provider: facebook
            client_id: '{your app''s oauth client id}'
            client_secret: '{your app''s oauth client secret}'
            scopes:
              - email
  ```

  ```json policy.json theme={null}
  {
    "on_http_request": [
      {
        "actions": [
          {
            "type": "oauth",
            "config": {
              "provider": "facebook",
              "client_id": "{your app's oauth client id}",
              "client_secret": "{your app's oauth client secret}",
              "scopes": [
                "email"
              ]
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

## Action result variables

The following variables are made available for use in subsequent expressions and
CEL interpolations after the action has run. Variable values will only apply
to the last action execution, results are not concatenated.

<ConfigField title="actions.ngrok.oauth.error" type="object">
  <ConfigChildren>
    <ConfigField title="actions.ngrok.oauth.error.code" type="string">
      Code for an error that occurred during the invocation of an action.
    </ConfigField>

    <ConfigField title="actions.ngrok.oauth.error.message" type="string">
      Message for an error that occurred during the invocation of an action.
    </ConfigField>
  </ConfigChildren>
</ConfigField>

<ConfigField title="actions.ngrok.oauth.identity" type="object">
  <ConfigChildren>
    <ConfigField title="actions.ngrok.oauth.identity.id" type="string">
      Unique identifier for the ngrok Identity entity.
    </ConfigField>

    <ConfigField title="actions.ngrok.oauth.identity.email" type="string">
      Email address of the authorized user from the provider.
    </ConfigField>

    <ConfigField title="actions.ngrok.oauth.identity.name" type="string">
      Name for the authorized user from the provider.
    </ConfigField>

    <ConfigField title="actions.ngrok.oauth.identity.provider_user_id" type="string">
      Identifier for the authorized user from the provider.
    </ConfigField>

    <ConfigField title="actions.ngrok.oauth.identity.current_provider_session_id" type="string">
      The current Identity session identifier for this request.
    </ConfigField>
  </ConfigChildren>
</ConfigField>

<ConfigField title="actions.ngrok.oauth" type="object">
  <ConfigChildren>
    <ConfigField title="actions.ngrok.oauth.access_token" type="string">
      The access token from the provider.
    </ConfigField>

    <ConfigField title="actions.ngrok.oauth.refresh_token" type="string">
      The refresh token from the provider.
    </ConfigField>

    <ConfigField title="actions.ngrok.oauth.expires_at" type="string">
      Timestamp when the current session will expire.
    </ConfigField>

    <ConfigField title="actions.ngrok.oauth.session_timed_out" type="boolean">
      Returns true when the session timed out.
    </ConfigField>

    <ConfigField title="actions.ngrok.oauth.session_max_duration_reached" type="boolean">
      Returns true when the current session reached the max duration.
    </ConfigField>

    <ConfigField title="actions.ngrok.oauth.userinfo_refreshed" type="boolean">
      Returns true when ngrok updates the user information on the identity.
    </ConfigField>
  </ConfigChildren>
</ConfigField>
