Privileged Access for Web Apps Overview | Twingate

Privileged Access for Web Apps Overview

Add per-request user identity to internal web apps behind a Twingate Gateway.

Beta

Twingate Privileged Access for Web Apps is currently available and free for up to five Resources. To start a free trial, contact Twingate.

Twingate Privileged Access for Web Apps

Twingate Privileged Access for Web Apps adds per-request user identity to internal web applications. When you put a web app behind a Twingate Gateway as a Web App Resource, the Gateway injects a signed JWT into every HTTP request. Your app verifies the JWT and gets the authenticated user’s identity without any OIDC integration, client secrets, or redirect flows. HTTPS support gives users secure https:// URLs that pass browser security checks, removing any “insecure connection” warnings.

Key benefits

Use Cases

How It Works

The Twingate Gateway acts as a Layer 7 reverse proxy between the Twingate Client and your web app. Before the Client can reach the Resource, the Twingate Controller authorizes the user and issues a Gateway Access Token (GAT) scoped to that user, device, and Resource. The Client presents the token to the Gateway when it opens the connection, and the Gateway injects it into every HTTP or HTTPS request it forwards upstream.

Browser → Twingate Client → Gateway → Your App
                                 ↓
                          [Injects headers]

Here is what happens on each request:

HTTPS

The Gateway issues certificates on demand from your CA, so there are no per-app certificates to manage. After terminating HTTPS, the Gateway forwards each request to your app with the same identity headers as any other Web App Resource.

JWKS Endpoint

Twingate exposes its public signing keys at a standard JWKS endpoint:

https://<your-tenant>.twingate.com/api/v1/jwk/ec

This endpoint is unauthenticated, following the JWKS convention. Most JWT libraries fetch and cache these keys automatically.

JWT Header

The Controller issues an ES256-signed JWT on every forwarded request. The token is a standard JWT in compact form (header.payload.signature), and its header looks like this:

{
  "alg": "ES256",
  "typ": "GAT",
  "kid": "a1b2c3d4"
}
Field Description
alg Used to tell the consumer what signing algorithm is used for verification purposes.
typ Always GAT, for Gateway Access Token. This is not the conventional JWT value.
kid Key ID identifying which JWKS key signed this token. Your JWT library uses it to pick the right key.

The typ field is GAT, not JWT

Some JWT libraries validate that typ equals JWT and reject anything else. If verification fails with a type or header error even though the signature is good, check whether your library enforces typ and configure it to accept GAT.

JWT Payload

Here is the full payload structure:

{
  "rnw": 1720003200,
  "jti": "a7f2e891-4c3d-48b6-9e1a-5d2f7b8c0e3a",
  "iss": "twingate",
  "aud": "tenant-slug",
  "exp": 1720040400,
  "iat": 1720000000,
  "ver": "1",
  "zver": "0.1.2405001",
  "cpk": "LS0tLS1CRUdJTi...LS0tLS0K",
  "resource": {
    "id": "UmVzb3VyY2U6MTIzNDU2Nzg5",
    "type": "WEB_APP",
    "address": "internal-dashboard.tenant.svc.cluster.local",
    "aliases": [
      "dashboard.internal"
    ],
    "gateway_metadata": {
      "downstream": {
        "port": 443
      },
      "upstream": {
        "port": 443
      },
      "request_header_rewrites": {}
    }
  },
  "user": {
    "id": "VXNlcjo1NTU1NQ==",
    "username": "jane.doe@company.com",
    "email": "jane.doe@company.com",
    "first_name": "Jane",
    "last_name": "Doe",
    "groups": [
      "Everyone",
      "twingate:authenticated",
      "engineering"
    ]
  },
  "device": {
    "id": "RGV2aWNlOjg4ODg4",
    "location": {
      "lat": 37.77,
      "lon": -122.42,
      "country": "US",
      "region": "California",
      "city": "San Francisco"
    }
  }
}

Common Token Claims

Claim Type Description
rnw Integer Unix timestamp for the renewal window.
jti String Unique JWT identifier (UUID).
aud String Audience — your Twingate network name.
exp Integer Unix timestamp after which the token is invalid. Your middleware should reject expired tokens.
iat Integer Unix timestamp when the token was created.
ver String Token format version.

User Claims

Claim Type Description
user.id String Twingate user ID. Stable across sessions for the same user.
user.username String The user’s email address or IdP username.
user.email String The user’s email address.
user.first_name String The user’s first name.
user.last_name String The user’s last name.
user.groups Array Twingate Group names that authorized access to this Resource. Always includes twingate:authenticated. Use these for authorization decisions in your app.

Device Claims

Claim Type Description
device.id String Twingate device ID. Identifies the specific device the request came from.
device.location.lat Number Latitude of the device’s location.
device.location.lon Number Longitude of the device’s location.
device.location.country String ISO 3166-1 alpha-2 country code of the device’s location.
device.location.region String Region or state of the device’s location.
device.location.city String City name of the device’s location.

Resource Claims

Claim Type Description
resource.id String Twingate Resource ID.
resource.type String Always WEB_APP for Web App Resources.
resource.address String The upstream address configured for this Resource.
resource.aliases Array DNS aliases configured for this Resource.
resource.gateway_metadata.downstream.port Integer The port on which the Twingate Client intercepts the user’s request.
resource.gateway_metadata.upstream.port Integer The port of the web application that the Gateway connects to.
resource.gateway_metadata.request_header_rewrites Object Header rewrite rules applied to requests.

Request Headers

The Gateway can inject custom HTTP headers into every forwarded request. Until you configure at least one header, your app receives an ordinary request with no identity or extra information injected.

Where Headers Are Defined

Headers come from two places, and both are opt-in:

The Gateway applies per-Resource rewrites after Gateway-wide headers, so a rewrite overrides a Gateway-wide header of the same name.

Configuring Headers

Each header is defined with a key and a value template. The key can be any HTTP header name. The value supports template variables that the Gateway replaces with request-specific data.

Available Template Variables

Variable Description Example Value
{{jwt}} The signed ES256 JWT containing the full user identity. eyJhbG...
{{username}} The user’s email address or username. user@company.com
{{groups}} Comma-separated list of Twingate Group names. Always includes the built-in twingate:authenticated group (and Everyone) in addition to the Groups you assign. twingate:authenticated,Everyone,engineering
{{clientGeoLatLong}} Client’s latitude and longitude. 37.7749,-122.4194
{{clientGeoCity}} Client’s city. San Francisco
{{clientGeoRegion}} Client’s region or state. California
{{clientGeoCountry}} Client’s country code. US

Example Configuration

The recommended configuration is to pass the JWT as a Bearer token for applications that can validate JWTs signed by Twingate. As a fallback, you can use plaintext headers, but make sure they come only from the Gateway:

Header Key Value Template
Authorization Bearer {{jwt}}
X-Twingate-User {{username}}
X-Twingate-Groups {{groups}}

Configuring Headers with Terraform

To configure headers with Terraform, you can use the twingate_web_app_resource resource for per-Resource header injection:

resource "twingate_web_app_resource" "internal_app" {
  name              = "Internal App"
  gateway_id        = twingate_gateway.main.id
  remote_network_id = twingate_remote_network.prod.id
  address           = "internal.acme.com"
  alias             = "app.int"
  downstream = {
    port = 80
  }
  upstream = {
    port = 8080
  }
  request_header_rewrites = {
    "X-Twingate-User" = "{{username}}"
  }
}

Configuring Headers with the Twingate Operator

If you deploy the Gateway with the Twingate Kubernetes Operator, you can define headers in your manifests rather than the Admin Console. Each surface expresses the same idea in a different shape, so check which one you are editing.

Gateway-wide headers are a map in your Helm values:

gateway:
  webApp:
    enabled: true
    requestHeaders:
      Authorization: "Bearer {{jwt}}"

Per-Resource rewrites are a list of name and value pairs on the TwingateResource:

apiVersion: twingate.com/v1beta
kind: TwingateResource
metadata:
  name: internal-dashboard
spec:
  type: WebApp
  name: "Internal Dashboard"
  address: internal-dashboard.default.svc.cluster.local
  alias: dashboard.internal
  gatewayRef:
    name: twingate-gateway
  downstream:
    port: 443
  upstream:
    port: 443
  requestHeaderRewrites:
    - name: X-Twingate-User
      value: "{{username}}"

If you let the operator create the Resource from a Service annotation instead, the same rewrites are a JSON object inside a string:

metadata:
  annotations:
    resource.twingate.com: "true"
    resource.twingate.com/type: "WebApp"
    resource.twingate.com/gatewayName: "example-gateway"
    resource.twingate.com/gatewayNamespace: "gateway-namespace"
    resource.twingate.com/downstreamPort: "443"
    resource.twingate.com/downstreamTLSMode: "TLS13"
    resource.twingate.com/requestHeaderRewrites: '{"Authorization": "Bearer {{jwt}}"}'

Getting Started

To add Privileged Access to your web app, you need:

HTTPS support requires the following in addition:

For CAs, you can choose from the following options:

For user devices, ensure that they trust the CA. This can be configured in the following ways:

The best way to get started is to install the Kubernetes Operator and work through the user guide.

See the developer guides for drop-in middleware you can add to your app in minutes. Guides are available for Express.js, Django, Next.js, and Next.js + Auth.js.

For off-the-shelf apps you run but don’t build, see the application integration guides. Apps like Grafana and Jenkins already support trusted-header authentication, so the Gateway can sign users in without any code changes.

Warning

Some SaaS apps use authentication and redirection mechanisms that conflict with the Twingate Gateway architecture. Connecting these SaaS apps as Twingate Web App Resources may cause unexpected behavior.

For general information about deploying Twingate Identity Firewall, see the Identity Firewall Overview.