Security & Access
Access Controls
Protect public URLs with per-endpoint policies. All rules are enforced at the edge before traffic reaches your service.
Configure through the dashboard or the API under Endpoint Settings → Authentication. Four modes available:
- None (Public) — No authentication required. Useful for public sites or webhooks.
- Basic Auth — Username/password protection with bcrypt hashing.
- Bearer / Token — Bearer token in the
AuthorizationorX-Tunnel-Tokenheader. Ideal for API access. - SSO (Unified RBAC) — OAuth providers with Role-Based Access Control. See SSO section below.
- Mutual TLS (mTLS) — Require clients to present a certificate during the TLS handshake. See Mutual TLS section below.
Additional edge-level protections:
- IP Allowlist — Restrict access to specific CIDR ranges (IPv4 and IPv6)
- Rate Limiting — Per-IP or per-endpoint request rate limits
# Configure basic auth via API
curl -X PUT https://api.ngris.com/v1/endpoints/{id}/settings \
-H "Authorization: Bearer $TOKEN" \
-d '{"auth_mode":"basic","basic_users":[{"username":"admin","password":"secret"}]}'
# Create WAF policy with IP restriction
curl -X POST https://api.ngris.com/v1/firewall/policies \
-H "Authorization: Bearer $TOKEN" \
-d '{"name":"block-ips","action":"block"}'
Unified RBAC
Unified Role-Based Access Control manages users, roles, and permissions centrally across all your endpoints.
Clients & Users
A "Client" represents a user or service account. Clients can authenticate via:
- Username/Password — For direct login
- OAuth/SSO — Linked to an identity provider
- Tokens — For programmatic access
Roles & Permissions
Roles define what a client can do. Restrict access based on:
- Allowed Paths — Whitelist URL paths (e.g.,
/api/*) - Denied Paths — Blacklist sensitive paths (e.g.,
/admin/**) - Allowed Methods — Restrict HTTP methods (e.g., GET only)
Team Members & Audit
An account can be shared with other people. The person who created the account is its owner; everyone else joins as a member. Owners and members differ only in permissions — resources belong to the account, not to any one person.
Inviting members
Invite teammates by email from Account Settings → Members. They receive an invitation link, accept it, and join the account with the role you assign.
- Owner — full control of the account, including billing, plan changes, and member management. The owner is always exempt from the member gate.
- Member — access governed by their assigned role / RBAC permissions. Non-owner members may only access the account when the plan grants the
account_membersentitlement.
Seat cap
The number of members an account may hold is capped by plans.max_members for the active plan (0 / unset = unlimited). Invitations beyond the cap are rejected. Downgrading to a plan without the account_members entitlement suspends existing non-owner memberships until the account upgrades again.
Account audit log
Every resource action on the account — endpoint, domain, certificate, firewall, API-key, billing, and organisation changes — is recorded in the account-scoped audit log, showing who acted, how they authenticated, and from which device. (Personal sign-in / password / 2FA events live on the per-user security surfaces, not here.)
account_members entitlement and the audit log requires the account_audit_log entitlement. See GET /v1/account/entitlements to check what the active account has.SSO / OIDC
Require org SSO for protected endpoints. Users authenticate via OAuth, and Ngris matches their subject ID to a client record with RBAC applied automatically.
Configure per-endpoint through Endpoint Settings → Authentication and select OAuth mode. Supported providers:
- Google — Google Workspace / Gmail
- GitHub — GitHub accounts and organizations
- Azure AD — Microsoft Entra ID
- Okta / Auth0 — Enterprise identity providers
- Custom OIDC — Keycloak, Authentik, Zitadel, and any OIDC-compliant provider
Setup Steps
- Configure OAuth 2.0 / OIDC credentials in your identity provider (Web Application, Authorization Code flow)
- Set the redirect URL to:
https://{your-subdomain}.ngris.io/_tunnel_auth/oauth/callback - Obtain OAuth subject identifiers (
subclaim for Google, username for GitHub,oidfor Azure) - Create endpoint clients in the dashboard: Users tab → Create Client → Enable OAuth/SSO → Enter Subject & Provider
- Assign roles via the Memberships tab
Mutual TLS (mTLS)
Require clients to present a certificate signed by a trusted Certificate Authority during the TLS handshake. Ngris manages the server-side certificates for every endpoint automatically — you only upload the client CAs you trust.
Enforcement happens at the TLS layer, before any HTTP request is parsed. Rejected connections never reach your origin.
1. Upload a Client CA
Go to Dashboard → Secure Tunnels → mTLS and click Upload CA. Paste a PEM-encoded CA certificate.
- One CA per upload — bundles (multiple certificates in one PEM) are rejected.
- Certificate must have
BasicConstraints: CA = true. Leaf certs are rejected. - Duplicates are detected by SHA-256 fingerprint per user.
- On upload, Ngris parses and stores Subject CN, Issuer CN, fingerprint, and validity window for display.
2. Enable mTLS on an Endpoint
Open the endpoint, go to Settings → Mutual TLS, pick a mode and select one or more CAs:
- Disabled — No client certificate is requested. Default.
- Optional — Request a certificate; accept the connection whether or not one is presented. Traffic-policy rules can then match on the presented cert.
- Required — Reject the TLS handshake unless the client presents a valid certificate signed by one of the selected CAs.
3. Attribute-Level Filtering (optional)
Once an endpoint accepts client certs, you can layer extra checks with a Require Client Certificate traffic-policy rule in the on_http_request phase. Match on:
- Subject CN — regex against the leaf certificate's Subject Common Name.
- SAN — regex matched against any DNS, email, or URI SAN.
- Issuer CN — regex against the Issuer Common Name.
All provided matchers are AND-ed together. Empty matchers are skipped. Use this to route, for example, only CN=admin certs to /admin/*.
Troubleshooting
- Clients see TLS handshake failure on Required mode — they are not presenting a client certificate, or the cert's issuer chain is not signed by any selected CA. Use
openssl s_client -connect host:443 -cert c.crt -key c.keyto inspect. - Expired CA — a CA's expiry is shown on the mTLS page; expired CAs are kept in the library but no longer validate chains. Upload the new CA and reselect on affected endpoints.
- Cannot delete a CA — detach it from every endpoint first (endpoint's Mutual TLS tab). Ngris refuses to delete in-use CAs.
# Upload a client CA
curl -X POST https://api.ngris.com/v1/client-cas \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Corporate Device CA","ca_pem":"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"}'
# Enable mTLS on an endpoint (mode + trusted CA IDs)
curl -X PUT https://api.ngris.com/v1/endpoints/{uuid}/mtls \
-H "Authorization: Bearer $TOKEN" \
-d '{"mode":"required","ca_ids":[12]}'
# Test with a client certificate
curl --cert client.crt --key client.key https://your-endpoint.ngris.io/
# Client without a cert, on a required endpoint — handshake rejected:
# curl: (56) OpenSSL SSL_read: error, errno 0
Endpoint authentication from the agent CLI
You don't have to open the dashboard to put an endpoint behind a login. The agent can attach HTTP Basic auth and/or mutual TLS to its endpoint at connect time straight from command-line flags — enforcement still happens at the edge, so nothing extra runs on your machine. The flags also work in the config file.
Basic auth
Pass --basic-auth user:pass to require a username and password. Repeat the flag for multiple users. The value is split on the first colon, so a password may itself contain colons; passwords must be at least 8 characters.
- The agent manages its own set of edge users. Re-running with a new
--basic-authlist replaces the users the agent created — users you added in the dashboard are left untouched. - Passwords are stored bcrypt-hashed and verified at the edge; the plaintext is never written to the endpoint's record.
Mutual TLS
Require clients to present a certificate with --mutual-tls <mode>. The modes match the Mutual TLS section above:
- disabled — clear mTLS on the endpoint. No CA needed.
- optional — request a certificate but accept the connection whether or not one is presented.
- required — reject the TLS handshake unless the client presents a valid certificate.
For optional and required, point --client-ca <file> at a single PEM-encoded CA certificate — the one that signs the client certs you trust. It must be one CA, not a bundle. Enabling mTLS (any mode other than disabled) requires the mTLS (mtls_attachment) entitlement on your plan; without it the agent logs a clear error and keeps serving traffic (the tunnel is never blocked).
Protect a writable WebFM server
The same flags work on every tunnel command, including the Web File Manager. Running ngris webfm <path> --rw exposes a world-writable file server — anyone who can reach the endpoint can upload, edit, and delete files. Always pair --rw with --basic-auth (or --mutual-tls); the agent prints a loud warning if you don't.
ngris to change them.# One Basic-auth user (password ≥ 8 chars)
ngris http 3000 --basic-auth alice:s3cretpw
# Multiple users — repeat the flag
ngris http 3000 --basic-auth alice:s3cretpw --basic-auth bob:hunter2!
# Require a client certificate signed by your CA (needs the mTLS entitlement)
ngris http 3000 --mutual-tls required --client-ca ./client-ca.pem
# Request a cert but accept clients without one
ngris http 3000 --mutual-tls optional --client-ca ./client-ca.pem
# Protect a read-write Web File Manager
ngris webfm ./site --rw --basic-auth admin:s3cretpw
Request Forwarding
When authentication succeeds, Ngris injects identity information into request headers before forwarding to your backend.
Standard Headers
Enable in Endpoint Settings to receive user context:
| Header | Description |
|---|---|
| X-User-ID | Internal ID of the authenticated client |
| X-User-Email | Email address of the user |
| X-User-Username | Username of the client |
| X-User-DisplayName | Display name of the user |
| X-User-Roles | Comma-separated list of assigned roles |
| X-Auth-Method | Method used (token, basic, session) |
| X-Forwarded-For | Original client IP address |
Variable Substitution
Use {{.VariableName}} in custom headers and cookies to inject dynamic user information:
| Variable | Description |
|---|---|
| {{.UserID}} | Client internal ID |
| {{.UserEmail}} | User email address |
| {{.UserRoles}} | Comma-separated roles |
| {{.ClientIP}} | Client IP address |
| {{.Metadata.KEY}} | Custom metadata field |
Request Signing
Verify requests come from Ngris with the X-Ngris-Signature header using HMAC-SHA256.
func verifySignature(header, secret string) bool {
parts := strings.Split(header, ".")
if len(parts) != 2 { return false }
payload, _ := base64.RawURLEncoding.DecodeString(parts[0])
signature, _ := base64.RawURLEncoding.DecodeString(parts[1])
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(payload)
expected := mac.Sum(nil)
return hmac.Equal(signature, expected)
}
Static Egress IP
Whitelist Ngris with partners and firewalls. Static egress IPs are available as an add-on on all paid plans.
Configure egress IPs through the dashboard under Endpoint Settings → Egress or via the API. Each static IP provides consistent outbound routing for your endpoints.