flexway
FRENTalk to an expert

Security

Closed by default, identity end to end.

Tokens from several issuers, scopes and roles read from the contract, API keys and client certificates bound to a tenant: what is not declared does not pass.

11 of the 12 shown delivered · since v0.1.0

What you expect from this domain

  • Authenticate applications, users and services (OIDC, JWT, mTLS)Delivered · since v0.1.0
  • Trusted intermediary between organisationsMultiple issuers, partner mTLS, token exchange, per-field encryption; declared purpose of use: candidatePartly · next to be scheduled
  • Consent, access traceabilityAccess audit built; consent decided by the customer's service, reachable through external-callPartly · next to be scheduled
Every market expectation
Identities declared in the catalogueIdentities declared in the catalogue
Every operation declares how callers identify themselves: token, API key, mTLS, trusted mesh or public; the catalogue counts them.Real console capture, demo data · v1.6.3

What it solves

Problem 1

One parameter too many gets through

An unexpected header or parameter reaches the service.

Flexway's answer: Closed by default: an undeclared header, parameter, method or origin is refused.

Problem 2

Every service redoes authorisation

Scopes and roles reimplemented service by service, with gaps.

Flexway's answer: Scopes and roles read from the contract's security and tags, checked once.

Problem 3

A tenant sees another's data

The tenant comes from a header the client controls.

Flexway's answer: The tenant is read from the verified identity; isolation is tested on every change.

How it works

Every step is a decision readable in the trace and in the console.

Your infrastructureflexwayAPI, AI and agent gatewayUnified Decision Chain (UDC)401identity refused: 40140301 Origin02 Identity03 Issuer04 Scopes05 Schema06 AuditOIDC tokenAPI keyClient certificateServicesYour infrastructureflexwayAPI, AI and agent gatewayUnified Decision Chain (UDC)40101 Origindeclarative CORS02 IdentityJWT, API key, mTLS or opaque token03 Issueriss and aud checked04 Scopesthe contract's05 Schemabody and parameters validated06 Auditchained decisionOIDC tokenAPI keyClient certificateServices

Security - Domain diagram: who calls, the decision steps, what is called, and where a request is refused.

  • OIDC token
  • API key
  • Client certificate
  1. Origin
  2. Identity
  3. Issuer
  4. Scopes
  5. Schema
  6. Audit
  • Services

identity refused: 401, 403

OIDC token
A caller holding an OIDC token: Flexway checks its signature, issuer, audience and scopes before any relay.
API key
A caller holding an API key: the key is a first-class identity, bound to operations and to a tenant.
Client certificate
A caller authenticated by a client certificate (mTLS): the certificate carries the caller's identity and tenant.
Origin
A browser's origin is checked against the declared CORS policy; an undeclared origin gets 403.
Identity
Flexway checks who is calling (OIDC token, API key or client certificate) and reads the tenant from the identity; no valid identity: 401.
Issuer
The token's issuer (iss) and audience (aud) are checked; several issuers can coexist.
Scopes
The required scopes and roles come from the contract; a caller out of scope gets 403.
Schema
Parameters and body are validated against the contract's schema; a non-conforming request gets 422 without reaching the upstream.
Audit
Every authorization decision is logged in a chained, verifiable audit, without request content.
Services
Your REST and gRPC services: they receive only the requests Flexway let through, under deadline and circuit breaker.
  • Line: one route
  • Interchange: shared decision
  • Request
  • Refusal
  • Your infrastructure
  1. Origindeclarative CORS
  2. IdentityJWT, API key, mTLS or opaque token
  3. Issueriss and aud checked
  4. Scopesthe contract's
  5. Schemabody and parameters validated
  6. Auditchained decision

Deploy Flexway: topologies and the GitOps configuration cycle

In detail

The essentials of each topic, with its status in the published release; unfold a card for the full text.

Tokens from several issuers, checked on every request

In part

JWTs from several issuers are checked on every request with cached keys, and opaque tokens through RFC 7662 introspection.

  • Cached JWKS, rotation without a wave of 401s
  • iss and aud checked, several issuers
  • none and HS* refused by default
See the detailHide the detail - Tokens from several issuers, checked on every request

Flexway validates JWTs with JWKS keys discovered and cached in the background; key rotation happens with no restart and no wave of 401s. The issuer (iss) and audience (aud) are checked, and several issuers from different providers coexist in one configuration (auth.issuers). An issuer can accept several audiences for the duration of a rename. By default only asymmetric algorithms are accepted: none and HS* are refused.

Opaque tokens are checked through RFC 7662 introspection (opaque_tokens), with the same rules as a JWT and a response cached without exceeding its expiry; an unreachable provider gives 503. The gateway consumes identities, it does not issue them: the issuer remains your organisation's own.

Binding a token to its holder, through an mTLS certificate (RFC 8705) or DPoP proof of possession (RFC 9449), is upcoming; the choice between the two remains open.

All the points

  • Cached JWKS, rotation without a wave of 401s
  • iss and aud checked, several issuers
  • none and HS* refused by default
  • Opaque tokens via RFC 7662 introspection
  • Sender-constrained tokens: planned

Features and status

  • JWT validation, cached JWKS keys with rotationDelivered · v0.1.0
  • iss and aud checked; several issuers in one configurationDelivered · v0.1.0
  • Opaque token introspection (RFC 7662)Delivered · v0.1.0
  • Sender-constrained tokens: mTLS (RFC 8705) or DPoP (RFC 9449)Planned
Read in the documentation : Wiring your identity provider

Scopes and roles read from the contract

Delivered · v0.1.0

The authentication requirement comes from the contract's security: no operation is served with a weaker requirement than the one declared.

  • Contract security = enforced requirement
  • oauth2 and openIdConnect scopes, bearer roles
  • Distinct 401 and 403, WWW-Authenticate
See the detailHide the detail - Scopes and roles read from the contract

The authentication requirement comes from the contract's security section, not from a separate table: scopes for oauth2 and openIdConnect, roles for http bearer, supplemented by x-flexway-scopes. An operation with no anonymous alternative requires an identity; tags carry no requirement. No operation is served with a weaker requirement than the one declared.

Roles are read from the claim named by roles_claim; without it, no role is satisfied. Refusals follow HTTP semantics - 401 when the identity is missing or fails verification, 403 when it is not sufficient - with WWW-Authenticate and an RFC 9457 body. Whether a resource belongs to a tenant is still checked by the service, the only one that knows its data.

All the points

  • Contract security = enforced requirement
  • oauth2 and openIdConnect scopes, bearer roles
  • No roles claim: no role satisfied
  • Distinct 401 and 403, WWW-Authenticate

Features and status

  • Scopes and roles derived from the contract's securityDelivered · v0.1.0
  • RFC 9110 semantics: 400/422, 401/403, 404/405, 429/503, 502/504Delivered · v0.1.0
  • Normative refusal headers: WWW-Authenticate, Allow, Retry-After, RateLimit-*Delivered · v0.1.0
Read in the documentation : Identity and zero trust

Closed by default, validated against the schema

Delivered · v0.1.0

What is not declared does not pass, and the body and parameters are validated against the contract's schema, with a 422 naming each field.

  • Undeclared header, parameter, method, origin: refused
  • 422 naming each field
  • RFC 9457, closed catalogue of codes
See the detailHide the detail - Closed by default, validated against the schema

Whatever is not declared does not pass: an undeclared header is removed, an undeclared query parameter is refused by name, an undeclared method receives 405 with Allow, a non-allowed origin is refused. CORS is declared as a policy, global or per host, and security response headers are set on every response.

Body and parameters are validated against the contract schema: 422 naming each faulty field, with a code taken from the JSON Schema keyword and renamable (errors.field_codes). The body is read only if the operation declares one, within the server.limits.max_body bound (413 beyond). The mode is set per host or per operation (x-flexway-validation) - full, params or off - and the allow list of headers and parameters is kept in every mode.

No upstream error is relayed as is: gateway refusals follow RFC 9457, with a closed catalogue of codes and a request_id and trace_id in the response, the details staying in the log.

All the points

  • Undeclared header, parameter, method, origin: refused
  • 422 naming each field
  • Bounded body, read only when declared
  • RFC 9457, closed catalogue of codes

Features and status

  • Closed by default: undeclared header, parameter, method or origin refusedDelivered · v0.1.0
  • Body and parameters validated against the contract's schemaDelivered · v0.1.0
  • Response security headers and declarative CORSDelivered · v0.1.0
  • No upstream error relayed as isDelivered · v0.1.0
  • RFC 9457 on every product route; stable, redirectable typeDelivered · v0.1.0
Read in the documentation : Errors

API keys and client certificates, bound and bounded

Delivered · v0.1.0

An API key or a client certificate remains possible, bounded by construction: bound to a tenant and to operations, never passed to the upstream.

  • Key in a header only, SHA-256 fingerprint
  • Bound to a tenant, operations and an expiry
  • Client mTLS verified or attested by a trusted peer
See the detailHide the detail - API keys and client certificates, bound and bounded

When a caller can produce neither a workload identity nor an OAuth token, an API key remains possible, constrained by design. It is presented in a header only (Authorization: ApiKey), never in a URL parameter; an apiKey scheme placed elsewhere is refused at load. The store keeps only the SHA-256 fingerprint, compared in constant time, and the key exists in clear only once, at creation. Each key is bound to a tenant, to named operations and to a mandatory expiry.

Rotation keeps two active entries during the switchover; revocation means removing the entry, re-read by each replica on reload, with no restart. A stable prefix (fwk_) lets secret scanners spot a key published by mistake, and each call carries the key's identifier, never its value, in the trace and the log.

A client certificate is verified by the TLS listener (server.tls) or attested by the edge through x-forwarded-client-cert, trusted from a trusted peer only; it is bound to a tenant and to operations (auth.mtls.clients). The contract decides which mechanism satisfies which alternative: a token never replaces a key, nor the reverse. Neither the key nor the attested certificate reaches the upstream, and an API key remains an identity, not an authorisation.

All the points

  • Key in a header only, SHA-256 fingerprint
  • Bound to a tenant, operations and an expiry
  • Two-entry rotation, revocation on reload
  • Client mTLS verified or attested by a trusted peer

Features and status

  • API keys and client mTLS as first-class identitiesDelivered · v0.1.0
Read in the documentation : API keys

Tenant isolation

Delivered · v1.1.0

The tenant comes from the verified identity, never from a client header, and counters and the authenticated cache are its own, with no sharing possible.

  • Tenant read from the token, client header overwritten
  • Counters indexed by tenant
  • Authenticated cache: tenant and subject key, tested continuously
See the detailHide the detail - Tenant isolation

The tenant comes from the verified identity - the claim declared for the issuer (tenant_claim) - and never from a client-supplied header, which can be forged. The gateway writes it upstream under auth.tenant_header; an incoming tenant header is overwritten. Rate and quota counters are indexed by tenant, with no possible sharing.

Rate limiting counts per caller (issuer and subject, otherwise the client address behind server.trusted_proxies), never per calling pod: two users behind the same server-side client have separate counters. An authenticated response is cached only with a tenant and subject key, declared by the operation alone; without tenant and subject, nothing is cached.

This cache isolation is held by a blocking test run on every change, with a counter-test that strips the subject from the key. Cross-tenant access is treated as a critical vulnerability, not a defect.

All the points

  • Tenant read from the token, client header overwritten
  • Counters indexed by tenant
  • Rate per caller, not per pod
  • Authenticated cache: tenant and subject key, tested continuously

Features and status

  • Rate per caller (token bucket)Delivered · v0.1.0
  • Continuous cross-tenant isolation test, a blocking prerequisiteDelivered · v1.1.0
  • Authenticated cache, isolated per tenant and subjectDelivered · v1.1.0
Read in the documentation : Multi-tenant isolation

Chained audit of authorisation decisions

Delivered · v0.1.0

Each authorisation decision can leave an audit line chained to the previous one, which makes a deletion or an alteration verifiable.

  • One line per decision, hashed subject
  • Verifiable seq, prev, hash chaining
  • Distroless non-root image, signed
See the detailHide the detail - Chained audit of authorisation decisions

audit.decisions writes one authz_decision line per decision - all of them, or refusals only - with the operation, the path template, the hashed subject and the agent chain. Each line is chained to the previous one (seq, prev, hash) per replica, which makes deletion or tampering verifiable. The log holds no personal data in clear.

The rest of defence in depth lies in the product itself: distroless non-root image, read-only filesystem, SBOM, signature and attestation on the image digest, no native plugin and no script in the configuration. The administration surface sits on a separate port and accepts no key. A timestamped, correlated and verifiable audit helps you meet the logging and cybersecurity requirements that apply to your platform.

All the points

  • One line per decision, hashed subject
  • Verifiable seq, prev, hash chaining
  • Distroless non-root image, signed
  • No third-party code in the process

Features and status

  • Chained audit log of authorisation decisionsDelivered · v0.1.0
  • SBOM, signature and keyless attestation on the digestDelivered · v0.1.0
Read in the documentation : Security posture

Configuration

The identity-and-cors example, as it ships with Flexway v1.6.3.

examples/identity-and-cors/flexway.yaml
# Two identity providers at once, the tenant from a signed claim, a browser application on its own
# origin. What each operation requires is in the contract, never here.
version: 1
contracts:
  openapi: ./openapi.yaml
upstreams:
  default:
    url: http://orders.internal:8080
auth:
  tenant_header: X-Tenant                       # written toward the upstream; a caller's value is overwritten
  issuers:
    - name: staff
      discovery: https://id.example.com/realms/staff/.well-known/openid-configuration
      audience: api
      roles_claim: realm_access.roles
    - name: customers
      discovery: https://login.example.net/.well-known/openid-configuration
      audience: api
      tenant_claim: org
policies:
  definitions:
    browser:
      type: cors
      config:
        allow_origins: ["https://app.example.com"]
        allow_credentials: true
        max_age: 10m
  chains:
    global: [browser]

Features

What is delivered in the published release v1.6.3, and what is coming; a feature is never shown as delivered before its release.

FeatureStatus
JWT validation, cached JWKS keys with rotationDelivered · v0.1.0
iss and aud checked; several issuers in one configurationDelivered · v0.1.0
Scopes and roles derived from the contract's securityDelivered · v0.1.0
Closed by default: undeclared header, parameter, method or origin refusedDelivered · v0.1.0
Body and parameters validated against the contract's schemaDelivered · v0.1.0
API keys and client mTLS as first-class identitiesDelivered · v0.1.0
Opaque token introspection (RFC 7662)Delivered · v0.1.0
Chained audit log of authorisation decisionsDelivered · v0.1.0
Sender-constrained tokens: mTLS (RFC 8705) or DPoP (RFC 9449)Planned
Effective policy chain per routeDelivered · v0.1.0
Local accounts and first admin, without an identity provider: generated initial password, forced change, TOTP for admins, shared lockDelivered · v0.1.0
Management of local accounts in the console: invitation, role and tenant, reset, MFA, deactivationDelivered · v0.1.0

Every feature

The other expectations of this domain

  • Coordination between farms and servicesCross-organisation exchange with a declared purpose: candidateTo be scheduled
  • Coordination between actorsMultiple issuers, partner mTLS, token exchange, per-field encryption; declared purpose of use: candidateTo be scheduled

The other domains

Let's talk about your gateway

Flexwiz is a young company: you talk directly with the person who founds it. Tell us what you want to run through Flexway. We talk about your infrastructure and your digital sovereignty requirements.

Online booking is coming soon; until then, an e-mail is enough.