Skip to content

OIDC Authentication

YipYap implements Knative Eventing’s OIDC authentication model in both directions, outbound deliveries attach an OIDC bearer token; the ingest endpoint verifies incoming tokens against a configured issuer. Combined with Knative’s EventPolicy CRD, this gives you fine-grained, cryptographically-verified access control over who can send events where.

YipYap supports three authentication postures:

  1. None (default), no OIDC. Anyone with the sink URL or integration key can post.
  2. External IdP, YipYap signs outbound tokens via a third-party IdP (Keycloak, Dex, Authentik, Okta, Auth0, Google, Azure AD) using client-credentials. Inbound verification targets that same IdP.
  3. Self-hosted JWKS (SaaS only), YipYap is the IdP for outbound deliveries. Each org gets a stable sub = https://console.yipyap.run/orgs/{org_id}. Consumers trust YipYap’s /.well-known/jwks.json directly, no external IdP needed. Not available in FOSS; self-hosters bring their own IdP.

On a cloudevent_http notification channel, set the auth config to oidc and fill in the token URL + client credentials. YipYap fetches a token via client-credentials grant and attaches Authorization: Bearer <jwt> to every outbound POST.

Example channel config (API form):

{
"sink_url": "https://broker-ingress.knative-eventing.svc.cluster.local/my-ns/default",
"mode": "binary",
"auth": {
"type": "oidc",
"oidc": {
"issuer": "https://dex.example.com",
"token_url": "https://dex.example.com/token",
"client_id": "yipyap-delivery",
"client_secret": "super-secret",
"audience": "https://broker-ingress.knative-eventing.svc.cluster.local/my-ns/default"
}
}
}

Tokens are cached per (issuer, audience, client_id) with a 30-second refresh-ahead window. Multiple YipYap replicas share the cache (process-local today; JetStream KV-backed in a future phase).

Inbound: verifying bearer tokens at ingest

Section titled “Inbound: verifying bearer tokens at ingest”

Configure per-org verification by storing JSON under the org setting key cloudevents.ingest.auth:

{
"type": "oidc",
"oidc": {
"issuer": "https://kubernetes.default.svc",
"jwks_url": "",
"audiences": [
"https://console.yipyap.run/orgs/your-org-id/ingest"
]
}
}

With this set, every ingest request must carry Authorization: Bearer <jwt>. YipYap validates it against the issuer’s JWKS (cached, respects Cache-Control) and records the verified sub claim on the resulting check row for audit.

Error-code mapping:

Verifier resultHTTP status
Valid token200 OK
Missing bearer401 Unauthorized
Expired / bad signature / malformed401 Unauthorized
Wrong issuer / wrong audience403 Forbidden
JWKS endpoint unreachable503 Service Unavailable (retryable)

On SaaS, YipYap publishes its own JWK Set at https://console.yipyap.run/.well-known/jwks.json. Each org has a stable sub; consumers configure YipYap as a trusted issuer in their Knative cluster.

Key rotation, weekly rotation with a 14-day overlap window. Old keys remain in JWKS for 14 days after they’re retired so tokens minted during the overlap keep validating. After 14 days, retired keys drop out of JWKS and any outstanding tokens signed with them fail verification.

Signing algorithms, YipYap’s JWK Set advertises public keys under one of these algs (default EdDSA / Ed25519):

  • EdDSA (Ed25519), default. Smallest keys, fastest sign/verify.
  • RS256, RS384, RS512, RSA PKCS#1 v1.5 with SHA-256/384/512.
  • PS256, PS384, PS512, RSA-PSS. Preferred modern RSA.
  • ES256, ES384, ES512, ECDSA on P-256/P-384/P-521.

Symmetric algorithms (HS*) and alg: none are explicitly excluded, they have no place in a public JWKS.

Knative’s EventPolicy CRD authorises specific identities to deliver events to a Broker, Channel, Sequence, or Parallel. Combine it with YipYap’s outbound OIDC to create fine-grained, per-org access control.

Recipe 1, allow only YipYap’s service account

Section titled “Recipe 1, allow only YipYap’s service account”

Shared external IdP (Okta/Auth0/Google). YipYap’s client-credentials flow produces a token with sub = client:yipyap-delivery.

apiVersion: eventing.knative.dev/v1alpha1
kind: EventPolicy
metadata:
name: allow-yipyap-delivery
namespace: my-ns
spec:
to:
- ref:
apiVersion: eventing.knative.dev/v1
kind: Broker
name: default
from:
- sub: "client:yipyap-delivery"

Only events with a verified sub = client:yipyap-delivery are accepted by the Broker; others are rejected with 403.

Recipe 2, allow a specific yipyap org (SaaS-only)

Section titled “Recipe 2, allow a specific yipyap org (SaaS-only)”

YipYap’s self-hosted JWKS produces tokens with sub = https://console.yipyap.run/orgs/{org_id}. Trust it in your cluster and write a per-org policy:

apiVersion: eventing.knative.dev/v1alpha1
kind: EventPolicy
metadata:
name: allow-yipyap-org-acme
namespace: my-ns
spec:
to:
- ref:
apiVersion: eventing.knative.dev/v1
kind: Broker
name: default
from:
- sub: "https://console.yipyap.run/orgs/01HY1..."

If you run multiple YipYap orgs against the same cluster (e.g. distinct environments), one policy per org gives you precise isolation.

Stack policies: separate policies for alert.* vs monitor.* vs maintenance.* let different teams own different subsets.

apiVersion: eventing.knative.dev/v1alpha1
kind: EventPolicy
metadata:
name: allow-yipyap-alerts-only
namespace: my-ns
spec:
to:
- ref:
apiVersion: eventing.knative.dev/v1
kind: Broker
name: alerts-broker
from:
- sub: "https://console.yipyap.run/orgs/01HY1..."
filters:
- cesql: "type LIKE 'run.yipyap.alert.%'"

The alerts-broker accepts only yipyap alert events from the named org. Monitor and maintenance events flow elsewhere.

  • Self-hosted JWKS is not available in FOSS. Bring your own IdP.
  • Dex, Keycloak, and Authentik are the tested options. Any compliant OIDC provider works.
  • YipYap’s outbound channel config accepts any IdP’s token URL, no vendor coupling.

Reply events: how authentication and validation interact

Section titled “Reply events: how authentication and validation interact”

Three annotation-only reply types let your sinks add context to an alert’s timeline by returning a CloudEvent in the HTTP response body:

  • run.yipyap.reply.alert.claimed.v1: a “claimed by” entry on the timeline.
  • run.yipyap.reply.alert.enriched.v1: attach structured context (links, log previews).
  • run.yipyap.reply.alert.linked.v1: attach an external reference (Jira, PagerDuty, etc.).

A reply must:

  1. Be a CloudEvent in the HTTP response body (structured application/cloudevents+json OR binary-mode ce-* headers plus body).
  2. Carry ce_alertref equal to the outbound event’s id. The dispatcher rejects replies whose ce_alertref doesn’t match a recent outbound event in its in-process LRU (24-hour retention window).
  3. Be opted in on the channel. Each cloudevent_http channel has an Accepted Replies configuration; only reply types you have checked will be acted on. Others are silently dropped (logged and counted in metrics, no timeline row).
  4. Not exceed the rate cap. Per (org, reply-type) cap defaults to 60/minute; configurable per channel.

The sub claim from OIDC verification is recorded on every timeline row for audit. State-mutating reply types (suppress, escalate, route, deregister, and the rest) require OIDC to be enabled on the channel; annotation-only replies are accepted either way.