Skip to content
PaloNexus
Request access Request

Bring your own IdP (Logto / OIDC)

PaloNexus governs agent egress with cryptographic agent identity (Decentralized Identifier / Verifiable Credential, DID/VC) that does not depend on the workforce identity provider (IdP) — egress works out of the box. This page is for the other identity seam: human workforce sign-in (the people who own agents, approve elevations, and operate the portal). The self-host overlay ships anonymous-passthrough by default; this runbook wires the organization’s IdP so the control plane verifies inbound human identity against that issuer.

Logto is the supported IdP — the worked example below. Okta, Entra ID, Auth0, Keycloak, and any standard OpenID Connect (OIDC) provider integrate through the same three env vars and the same SCIM (System for Cross-domain Identity Management) /v1/directory seam; only the issuer URLs differ. Shipped connectors for the others are near-term roadmap, not a limitation of the standards path.

Three public URLs + one audience. For Logto (tenant YOUR-TENANT):

ValueEnv varLogto example
IssuerOIDC_ISSUERhttps://YOUR-TENANT.logto.app/oidc
JWKSOIDC_JWKS_URLhttps://YOUR-TENANT.logto.app/oidc/jwks
AudienceOIDC_AUDIENCEpalonexus (the registered API resource indicator)

These are not secrets (public discovery URLs) — they live in a Kustomize component, not a Secret.

Step 1 — register PaloNexus in Logto (fresh tenant)

Section titled “Step 1 — register PaloNexus in Logto (fresh tenant)”
  1. Create an API resource named e.g. PaloNexus with API identifier palonexus. This identifier is the OIDC_AUDIENCE — access tokens must carry it as aud.
  2. Create an application for the human sign-in surface (the portal / the SSO front door). Note its issuer is the tenant’s /oidc endpoint above.
  3. Grab the issuer and JWKS (JSON Web Key Set) URLs from the tenant’s OIDC discovery (https://YOUR-TENANT.logto.app/oidc/.well-known/openid-configuration).

Any OIDC IdP: register an app + an API/audience, then read issuer and jwks_uri from that provider’s /.well-known/openid-configuration. Okta/Entra/Auth0/Keycloak all expose it.

Step 2 — enable the oidc Kustomize component

Section titled “Step 2 — enable the oidc Kustomize component”

The self-host overlay strips the built-in Dex OIDC vars (anonymous-passthrough). To point at the organization’s issuer, enable the oidc component and remove the strip patch (they conflict — the component sets the vars the strip patch removes):

In deploy/kustomize/overlays/selfhost/kustomization.yaml:

  1. Under components:, uncomment - ../../components/oidc.
  2. In patches:, delete the three op: remove … /env/0 lines (the anonymous-passthrough patch). The component re-adds OIDC; leaving the strip would undo it.

Set the issuer values by editing deploy/kustomize/components/oidc/kustomization.yaml (replace YOUR-TENANT.logto.app and the audience). Render to confirm:

Terminal window
make render-selfhost | grep -A1 OIDC_ISSUER # shows the configured issuer + jwks + audience

Apply (or make install-selfhost):

Terminal window
kubectl apply -k deploy/kustomize/overlays/selfhost --load-restrictor LoadRestrictionsNone
kubectl -n palonexus rollout status deploy/control-plane

The control plane now verifies inbound bearer JSON Web Tokens (JWTs) against the IdP’s JWKS, requiring iss == OIDC_ISSUER and OIDC_AUDIENCE ∈ aud. A token from the configured IdP is accepted; anything else is denied (fail-closed). Egress decisions are unchanged.

Step 3 — push the workforce directory (SCIM / API)

Section titled “Step 3 — push the workforce directory (SCIM / API)”

Human ownership, approval authority, and the revocation cascade key off a stable directory subject (not email). Feed the workforce directory into agent-idp’s directory seam so those subjects resolve:

Terminal window
# Full-snapshot reconcile (the supported model — joiner/mover/leaver):
curl -sS -X POST "$AGENT_IDP_URL/v1/directory/sync" \
-H 'content-type: application/json' \
-d @your-directory-snapshot.json

The snapshot maps each employee to a stable employeeId subject + org/group membership; a leaver in a later snapshot triggers the revocation cascade (agents owned by that subject lose their delegations). See Connect agents to enterprise authority for the schema. A turnkey vendor SCIM connector (Logto/Okta push) is near-term roadmap; today the snapshot is pushed from the directory of record (the seeder in seed-logto/ is the worked example for Logto, and a template for any source).

Terminal window
# A human token from the configured IdP resolves to a stable subject:
curl -sS -X POST "$AGENT_IDP_URL/v1/identity/resolve" \
-H 'content-type: application/json' -d '{"token":"<a real login JWT from your IdP>"}'
# -> {"subject":"NST-1011", "source":"scim", ...} (not "unresolved")
# An inbound call with that token is accepted at /authz; without it, denied.

Acceptance: a real login token from the configured IdP is verified at /authz (right iss/aud), resolves to a stable workforce subject via /v1/identity/resolve, and that subject can own agents / approve elevations in the portal. Removing the component (or supplying a token from a different issuer) fails closed.

  • Logto is the supported IdP (worked example + seeder). Other OIDC IdPs use the identical three-env-var + SCIM-snapshot path; shipped vendor connectors are roadmap (BACKLOG → Deferred IdP Integrations).
  • Real JWT/JWKS verification is enforced at the control-plane edge; /v1/identity/resolve MVP trusts decoded claims from that verified edge (see the IdP-support concept page).
  • Docker Compose has its own OIDC turn-on (3 env vars in .env); see Docker Compose. This page is the Kubernetes equivalent.