Combine Authentication Methods
Some services need to support different groups of users with different types of credentials. Internal teams might use static IPs, but external users authenticate using JWTs. With ngrok’s engine, you can let both types of users through safely without making any changes to your upstream service.
This example walks you through how to apply multiple authentication layers to a single endpoint using action result variables and expressions that mimic an OR
operator.
You'll allow requests from trusted IPs OR
those containing valid JWTs, and then reject all others.
1. Start an endpoint for your service
Start an internal Agent Endpoint, replacing $PORT
based on where your service listens.
You can also use one of our SDKs or the Kubernetes Operator.
Loading…
2. Reserve a domain
Navigate to the Domains section of the ngrok dashboard and click New + to reserve a free static domain like https://your-service.ngrok.app
or a custom domain you already own.
We'll refer to this domain as $NGROK_DOMAIN
from here on out.
3. Create a Cloud Endpoint
Navigate to the Endpoints section of the ngrok dashboard, then click New + and Cloud Endpoint.
In the URL field, enter the domain you just reserved to finish creating your Cloud Endpoint.
4. Add layers of authentication with Traffic Policy
While still viewing your new Cloud Endpoint in the dashboard, copy and paste the policy below into the Traffic Policy editor. You will need to change:
$TRUSTED_IP_FOO
/$TRUSTED_IP_BAR
: Replace with public IPs of those who should have access to your service or an IP policy in your ngrok dashboard.$YOUR_JWT_DOMAIN
: The domain name for your tenant at your JWT provider—for example, with Auth0, it looks something likehttps://example.us.auth0
.
Loading…
What's happening here?
This policy has three logical sections, where the first two allow traffic to reach your upstream after authenticating with one method OR
another, and the third is a catch-all error response for requests that fail to authenticate against any method.
The first section checks every HTTP request to see if its source IP matches one on your allow
list for restrict-ips
, but doesn't actually enforce the restriction there.
Instead, the expression that follows the first action checks whether the restrict-ips
action result variable actions.ngrok.restrict_ips.action
is set to allow
, which means that it would've allowed the request directly if you had set enforce: true
.
If this expression is true, then the policy forwards the request to your upstream service.
If it's false—the request didn't match the IP allow
list—then it's instead forwarded based on whether or not it contains a valid JWT token (which may come from a couple different places).
If it does, then the policy forwards the request to your upstream service.
Finally, the policy denies all requests that did not authenticate either by IP or JWT and delivers a custom HTML response.
6. Try out your endpoint
Visit the domain you reserved either in the browser or in the terminal using a tool like curl
.
You should see the app or service at the port connected to your internal Agent Endpoint.
Add your JWT as a header to verify your jwt-validation
action works as expected.
Loading…
What's next?
- Layer in more authentication mechanisms, like the
oauth
orbasic-auth
actions using the same pattern of checking the subsequent action result variables with an expression. - Use the action result variables and CEL interpolation to add specific error messages to your catch-all
custom-response
action. - View your traffic in Traffic Inspector to see requests that failed to authenticate but should have—for example, maybe a specific IP address is missing from your
restrict-ips
allow list or a user who doesn't realize they're using an invalid JWT token.