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:
- They are only available for some identity providers
- They come with a number of limitations
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.
Cookie | Description |
---|---|
session | Used to track an authenticated user. |
nonce | Used to secure the authentication flow. |
Reference
Configuration
Parameter | Default | Description |
---|---|---|
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. |
Scopes | A list of additional scopes to request when users authenticate with the identity provider. | |
Auth Check Interval | 0 | When 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 Timeout | 0 | If 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 Duration | 0 | An authenticated client session may never last longer than this duration. If 0, no maximum duration is enforced. |
Options Passthrough | false | Don'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.
Header | Description |
---|---|
ngrok-auth-user-id | Provider-defined identifier of the authorized user. |
ngrok-auth-user-name | Full name of the authorized user. |
ngrok-auth-user-email | Authorized user's primary email address. |
ngrok-auth-oauth-access-token | The user's OAuth access token. Undefined when using a managed application. |
ngrok-auth-oauth-refresh-token | The 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.
Path | Description |
---|---|
/auth/authn | Redirect 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/logout | Logs 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
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
andngrok-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.
Plan | MAUs |
---|---|
Free | 5 |
Personal | 50 |
Pro | Unlimited, usage-based-pricing |
Enterprise | Unlimited, usage-based-pricing |
Supported Providers
ngrok currently supports the following OAuth providers:
Provider | Provider Identifier | Managed App Available | Integration Guide |
---|---|---|---|
Amazon | amazon | no | Documentation |
facebook | no | Documentation | |
GitHub | github | yes | Documentation |
GitLab | gitlab | yes | Documentation |
google | yes | Documentation | |
linkedin | yes | Documentation | |
Microsoft | microsoft | yes | Documentation |
Twitch | twitch | yes | Documentation |
Try it out
Consult the step-by-step integration guides we've written for supported providers.