Skip to main content

OAuth


Overview

The OAuth module enforces an OAuth authentication flow in front of your HTTP endpoints. Any client accessing an OAuth-protected endpoint will be redirected to a chosen identity provider (e.g. Google) for authentication. When they are redirected back to your endpoint, the ngrok edge checks an optional set of authorization constraints (e.g. email address). If authorized, the request is forwarded to your upstream application and ngrok sets a cookie to avoid repeating the authentication flow.

You configure the OAuth module with an identity provider name, your OAuth app's client ID and client secret, and an optional set of authorization constraints.

To get started faster, ngrok maintains managed OAuth apps for some identity providers so you don't need to bring your own client id and client secret. These managed OAuth applications are shared among ngrok accounts and have additional limitations.

We've written integration guides for every supported provider to make it easy for you to get started.

Quickstart

Agent CLI

Authenticate
ngrok http 80 --oauth google
Authenticate + Authorize by email and domain
ngrok http 80 \
--oauth google \
--oauth-allow-email kate.libby@gmail.com \
--oauth-allow-domain acme.org
Authenticate with your own OAuth app
ngrok http 80 \
--oauth microsoft \
--oauth-client-id "{client id}" \
--oauth-client-secret "{client secret}"
Customize requested authentication scopes
ngrok http 80 \
--oauth github \
--oauth-client-id "{client id}" \
--oauth-client-secret "{client secret}" \
--oauth-scope "repo" \
--oauth-scope "user"

Agent Configuration File

Authenticate
tunnels:
example:
proto: http
addr: 80
oauth:
provider: "google"
Authenticate + Authorize by email and domain
tunnels:
example:
proto: http
addr: 80
oauth:
provider: "google"
allow_domains: ["example.com", "acme.org"]
allow_emails: ["kate.libby@gmail.com"]
Authenticate with your own OAuth app
tunnels:
example:
proto: http
addr: 80
oauth:
provider: "microsoft"
client_id: "{client id}"
client_secret: "{client secret}"
Customize requested authentication scopes
tunnels:
example:
proto: http
addr: 80
oauth:
provider: "github"
client_id: "{client id}"
client_secret: "{client secret}"
scopes: ["repo", "user"]

SSH

Authenticate
ssh -R 443:localhost:80 connect.ngrok-agent.com http --oauth=google
Authenticate + Authorize by email and domain
ssh -R 443:localhost:80 connect.ngrok-agent.com http \
--oauth google \
--oauth-allow-email kate.libby@gmail.com \
--oauth-allow-domain acme.org
Authenticate with your own OAuth app
ssh -R 443:localhost:80 connect.ngrok-agent.com http \
--oauth microsoft \
--oauth-client-id "{client id}" \
--oauth-client-secret "{client secret}"
Customize requested authentication scopes
ssh -R 443:localhost:80 connect.ngrok-agent.com http \
--oauth github \
--oauth-client-id "{client id}" \
--oauth-client-secret "{client secret}" \
--oauth-scope "repo" \
--oauth-scope "user"

Go SDK

Authenticate
import (
"context"
"net"

"golang.ngrok.com/ngrok"
"golang.ngrok.com/ngrok/config"
)

func listenOAuth(ctx context.Context) net.Listener {
listener, _ := ngrok.Listen(ctx,
config.HTTPEndpoint(
config.WithOAuth("google"),
),
ngrok.WithAuthtokenFromEnv(),
)
return listener
}
Authenticate + Authorize by email and domain
import (
"context"
"net"

"golang.ngrok.com/ngrok"
"golang.ngrok.com/ngrok/config"
)

func listenOAuth(ctx context.Context) net.Listener {
listener, _ := ngrok.Listen(ctx,
config.HTTPEndpoint(
config.WithOAuth("google"),
config.WithAllowOAuthEmail("kate.libby@gmail.com"),
config.WithAllowOAuthDomain("acme.org"),
),
ngrok.WithAuthtokenFromEnv(),
)
return listener
}
Authenticate with your own OAuth app
import (
"context"
"net"

"golang.ngrok.com/ngrok"
"golang.ngrok.com/ngrok/config"
)

func listenOAuth(ctx context.Context) net.Listener {
listener, _ := ngrok.Listen(ctx,
config.HTTPEndpoint(
config.WithOAuth("microsoft"),
config.WithOAuthClientID("{client id}"),
config.WithOAuthClientSecret("{client secret}"),
),
ngrok.WithAuthtokenFromEnv(),
)
return listener
}
Customize requested authentication scopes
import (
"context"
"net"

"golang.ngrok.com/ngrok"
"golang.ngrok.com/ngrok/config"
)

func listenOAuth(ctx context.Context) net.Listener {
listener, _ := ngrok.Listen(ctx,
config.HTTPEndpoint(
config.WithOAuth("github"),
config.WithOAuthClientID("{client id}"),
config.WithOAuthClientSecret("{client secret}"),
config.WithOAuthScope("repo", "user"),
),
ngrok.WithAuthtokenFromEnv(),
)
return listener
}

Rust SDK

Authenticate
use ngrok::prelude::*;

async fn start_tunnel() -> anyhow::Result<impl Tunnel> {
let sess = ngrok::Session::builder()
.authtoken_from_env()
.connect()
.await?;
let tun = sess
.http_endpoint()
.oauth(OauthOptions::new("google"))
.listen()
.await?;
println!("Listening on URL: {:?}", tun.url());
Ok(tun)
}
Authenticate + Authorize by email and domain
use ngrok::prelude::*;

async fn start_tunnel() -> anyhow::Result<impl Tunnel> {
let sess = ngrok::Session::builder()
.authtoken_from_env()
.connect()
.await?;
let tun = sess
.http_endpoint()
.oauth(OauthOptions::new("google")
.allow_email("kate.libby@gmail.com")
.allow_domain("acme.org")
)
.listen()
.await?;
println!("Listening on URL: {:?}", tun.url());
Ok(tun)
}
Authenticate with your own OAuth app
use ngrok::prelude::*;

async fn start_tunnel() -> anyhow::Result<impl Tunnel> {
let sess = ngrok::Session::builder()
.authtoken_from_env()
.connect()
.await?;
let tun = sess
.http_endpoint()
.oauth(OauthOptions::new("microsoft")
.client_id("{client id}")
.client_secret("{client secret}")
)
.listen()
.await?;
println!("Listening on URL: {:?}", tun.url());
Ok(tun)
}
Customize requested authentication scopes
use ngrok::prelude::*;

async fn start_tunnel() -> anyhow::Result<impl Tunnel> {
let sess = ngrok::Session::builder()
.authtoken_from_env()
.connect()
.await?;
let tun = sess
.http_endpoint()
.oauth(OauthOptions::new("github")
.client_id("{client id}")
.client_secret("{client secret}")
.scope("repo")
.scope("user")
)
.listen()
.await?;
println!("Listening on URL: {:?}", tun.url());
Ok(tun)
}

Kubernetes Ingress Controller

Authenticate
---
kind: NgrokModuleSet
apiVersion: ingress.k8s.ngrok.com/v1alpha1
metadata:
name: ngrok-module-set
modules:
oauth:
google:
optionsPassthrough: false
inactivityTimeout: 4h
maximumDuration: 24h
authCheckInterval: 1h
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
k8s.ngrok.com/modules: ngrok-module-set
spec:
ingressClassName: ngrok
rules:
- host: your-domain.ngrok.app
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80
Authenticate + Authorize by email and domain
---
kind: NgrokModuleSet
apiVersion: ingress.k8s.ngrok.com/v1alpha1
metadata:
name: ngrok-module-set
modules:
oauth:
google:
emailAddresses: ["kate.libby@gmail.com"]
emailDomains: ["acme.org"]
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
k8s.ngrok.com/modules: ngrok-module-set
spec:
ingressClassName: ngrok
rules:
- host: your-domain.ngrok.app
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80
Authenticate with your own OAuth app
---
kind: Secret
apiVersion: v1
metadata:
name: ngrok-oauth-secret
type: Opaque
data:
CLIENT_SECRET: "<base64-encoded-client-secret>"
---
kind: NgrokModuleSet
apiVersion: ingress.k8s.ngrok.com/v1alpha1
metadata:
name: ngrok-module-set
modules:
oauth:
microsoft:
clientId: "{client id}"
clientSecret:
name: ngrok-oauth-secret
key: CLIENT_SECRET
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
k8s.ngrok.com/modules: ngrok-module-set
spec:
ingressClassName: ngrok
rules:
- host: your-domain.ngrok.app
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80
Customize requested authentication scopes
---
kind: Secret
apiVersion: v1
metadata:
name: ngrok-oauth-secret
type: Opaque
data:
CLIENT_SECRET: "<base64-encoded-client-secret>"
---
kind: NgrokModuleSet
apiVersion: ingress.k8s.ngrok.com/v1alpha1
metadata:
name: ngrok-module-set
modules:
oauth:
github:
clientId: "{client id}"
clientSecret:
name: ngrok-oauth-secret
key: CLIENT_SECRET
scopes: ["repo", "user"]
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
k8s.ngrok.com/modules: ngrok-module-set
spec:
ingressClassName: ngrok
rules:
- host: your-domain.ngrok.app
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80

Edges

OAuth is a supported HTTPS Edge module which can be applied to routes.

Behavior

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:

  • Check any authorization constraints you've defined (like allowed emails or allowed email domains). If the user is not authorized, ngrok renders an error and prompts them to try logging in again.
  • Sets a session cookie 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 /.

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 backchannel request to the identity provider; it is transparent to the user and they do not go through a reauthentication flow.

The following circumstances trigger refresh and authorization re-evaluation:

  • On a periodic interval defined by the the Auth Check Interval parameter.
  • If you update the OAuth configuration of the endpoint by restarting your agent with a new configuration.
  • If you update the OAuth configuration of the endpoint by modifying your Edge.

If a previously authenticated user becomes unauthorized because their identity provider information changed or because the OAuth module 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 module without setting up your own OAuth apps with the identity providers. More practically, this means you can use the OAuth module without configuring a client id and client secret.

Managed applications are great for getting started but:

App Users

ngrok's App Users 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 OAuth module, their App User record is created or updated.

You may also use App Users to remotely log a user out by revoking a session.

Cookies

This module sets two cookies in its operation. Cookies values are opaque to the upstream application and must not be modified.

CookieDescription
sessionUsed to track an authenticated user.
nonceUsed to secure the authentication flow.

Reference

Configuration

ParameterDefaultDescription
Provider-The identifier of the OAuth identity provider to use for authentication. Supported OAuth Providers
Client ID-Your OAuth app's Client ID. Leave this empty if you want to use a managed application.
Client Secret-Your OAuth app's Client Secret. Leave this empty if you want to use a managed application.
Allowed Emails-If specified, only users whose emails match a value in this list will be allowed.
Allowed Email Domains-If specified, only users whose emails match one of the given domains in this list will be allowed.
ScopesA list of additional scopes to request when users authenticate with the identity provider.
Auth Check Interval0When a request is received after this interval has passed since the last auth check or the initial authentication, ngrok will re-validate its authorization constraints. As part of this process, ngrok refreshes data about the authenticated user from the identity provider. If zero, authorization is only ever checked during an authentication flow.
Inactivity Timeout0If an authenticated client does not make a request to the endpoint within this duration, they are forced to reauthenticate. If 0, no inactivity timeout is enforced.
Maximum Duration0An authenticated client session may never last longer than this duration. If 0, no maximum duration is enforced.
Options PassthroughfalseDon't enforce authentication on OPTIONS requests. Useful if this endpoint needs to be accessible via CORS.

Upstream Headers

This module adds headers to the HTTP request sent to your upstream server with details about the OAuth user who has authenticated. These headers will not be set for OPTIONS requests if you enable options passthrough.

HeaderDescription
ngrok-auth-user-idProvider-defined identifier of the authorized user.
ngrok-auth-user-nameFull name of the authorized user.
ngrok-auth-user-emailAuthorized user's primary email address.
ngrok-auth-oauth-access-tokenThe user's OAuth access token. Undefined when using a managed application.
ngrok-auth-oauth-refresh-tokenThe user's OAuth refresh token. Undefefined when using a managed application.

Special Paths

Upstream applications behind endpoints with this module enabled do not receive any requests to paths beginning with /auth/. Your application may redirect clients to the following paths to invoke different behaviors.

PathDescription
/auth/authnRedirect users to this path to explicitly begin an authentication flow. After authentication, users will be redirected to /. If the IdP supports it, ngrok will attempt to instruct the IdP to force reauthentication which will force users to re-enter their credentials with the IdP even if they were already logged in.
/auth/logoutLogs the user out by clearing their session cookie. Redirect users to this path to log them out.

Events

When this module is enabled, it populates the following fields in the http_request_complete.v0 event:

Fields
oauth.app_client_id
oauth.decision
oauth.user.id
oauth.user.name

Errors

note

This documentation is incomplete at this time. We're working to improve it with a full list of errors.

Limits

Managed Applications

Managed OAuth applications are owned by ngrok and have limitations to prevent abuse.

  • With a managed oauth application you may not pass custom scopes.
  • The upstream headers ngrok-auth-oauth-access-token and ngrok-auth-oauth-refresh-token are not sent to your application.

MAUs

MAU stands for "Monthly Active User". Monthly Active Users are the number of uniquely authenticated OAuth users who have accessed your endpoints within a month.

OAuth MAU limits are enforced account-wide, they are not enforced on a per-endpoint basis.

An authenticated user with the same ID from the identity provider is counted as a single MAU even if they connect to multiple endpoints on your account.

PlanMAUs
Free5
Personal50
ProUnlimited, usage-based-pricing
EnterpriseUnlimited, usage-based-pricing

Supported Providers

ngrok currently supports the following OAuth providers:

ProviderProvider IdentifierManaged App AvailableIntegration Guide
AmazonamazonnoDocumentation
FacebookfacebooknoDocumentation
GitHubgithubyesDocumentation
GitLabgitlabyesDocumentation
GooglegoogleyesDocumentation
LinkedInlinkedinyesDocumentation
MicrosoftmicrosoftyesDocumentation
TwitchtwitchyesDocumentation

Try it out

Consult the step-by-step integration guides we've written for supported providers.