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 Authorization or X-Tunnel-Token header. 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 via API
# 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)
See also: API reference for managing Clients and Roles.

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_members entitlement.

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.)

Plan-gated: Team members require the 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

  1. Configure OAuth 2.0 / OIDC credentials in your identity provider (Web Application, Authorization Code flow)
  2. Set the redirect URL to: https://{your-subdomain}.ngris.io/_tunnel_auth/oauth/callback
  3. Obtain OAuth subject identifiers (sub claim for Google, username for GitHub, oid for Azure)
  4. Create endpoint clients in the dashboard: Users tab → Create Client → Enable OAuth/SSO → Enter Subject & Provider
  5. Assign roles via the Memberships tab
Tip: Account-wide defaults (endpoint SSO requirement, redaction, retention) are set in the dashboard under Account Settings. SSO configuration requires admin privileges.

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.
Scope: mTLS enforcement is per-endpoint and applies to HTTPS, HTTP/2, and HTTP/3 (QUIC). Configuration changes propagate within 60 seconds without restarting anything.

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.key to 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.
mTLS via API
# 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-auth list 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.

Applied once, at connect. Endpoint auth is attached right after the agent authenticates. A running agent does not re-read the flags — restart ngris to change them.
OAuth from the CLI isn't available yet. Per-endpoint OAuth/SSO providers carry client credentials, so they're configured in the dashboard for now — see SSO / OIDC above. Basic auth and mutual TLS are the CLI-native options today.
Endpoint auth from the CLI
# 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-IDInternal ID of the authenticated client
X-User-EmailEmail address of the user
X-User-UsernameUsername of the client
X-User-DisplayNameDisplay name of the user
X-User-RolesComma-separated list of assigned roles
X-Auth-MethodMethod used (token, basic, session)
X-Forwarded-ForOriginal 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.

Tip: Always check the timestamp in the payload to prevent replay attacks. Reject signatures older than 5 minutes.
Verify request signature (Go)
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.

Add-on: Dedicated egress IPs start at $10/month. Shared egress IPs are available on Pro plans and above. Contact support for dedicated provisioning.
Iris