# Authentication & Access

> How users log in to psLens, the deliberate scope decision behind no in-app RBAC, SSO via reverse proxy today, and native SSO on the roadmap.

---

LLMS index: [llms.txt](/llms.txt)

---

This page covers how end users authenticate to psLens, what access controls exist (and which deliberately don't), and how to front psLens with your existing identity provider today.

For SSO, see [SSO Today](#sso-today-reverse-proxy).

---

## 1. How Users Log In Today

psLens ships with **optional email magic-link authentication**. It is off by default in the shipped `config.yaml` and **must be turned on for production deployments**.

When `auth.enabled: true`:

1. User visits any psLens URL → redirected to `/login`.
2. User enters their email address.
3. psLens emails a one-time verification code to that address (only if the address is on the configured `AuthorizedUsers` allowlist).
4. User enters the code at `/verify-code`.
5. Session created in NATS KV, identified by an HTTP-only `psLens_auth` cookie.

|              Property               |                        Value                         |
| ----------------------------------- | ---------------------------------------------------- |
| Mechanism                           | Email one-time code (no passwords)                   |
| Session storage                     | NATS KV bucket `auth-sessions`                       |
| Session TTL                         | 1 year (configurable)                                |
| Cookie                              | `psLens_auth`, HTTP-only                             |
| User allowlist                      | `AuthorizedUsers` in `config.yaml`, case-insensitive |
| Public endpoints (no auth required) | `/healthz`, `/static/*`, the auth flow itself        |

There are no end-user passwords for psLens to store, leak, hash, or rotate.

**Disabling auth entirely** is supported only for sandbox or trusted-network deployments. The shipped config defaults to disabled so a first-time installer can get to a working UI quickly. Flip it on before exposing the instance.

---

## 2. The Deliberate Scope Decision: No In-App RBAC

psLens has **no role-based access control inside the application.** Every authenticated user sees the same set of metadata, can run the same reports, and can browse the same PS objects.

This is intentional, not an oversight:

- psLens is **read-only**. It cannot modify PeopleSoft. The worst an authenticated user can do is read metadata.
- The query surface is **whitelisted on the PeopleSoft side** by the SWS framework. Even psLens itself cannot query anything off-list. See [Security & Trust](/security/).
- The access boundary therefore lives at **who is on the `AuthorizedUsers` list**, not at "what role does this user have inside psLens?". If a user shouldn't see PS metadata at all, they shouldn't have a psLens login.

For most customers, the population of people who need psLens (PS developers, sec admins, sys admins, business analysts doing audit work) is small and homogeneous. Adding in-app roles would create configuration overhead without changing the actual blast radius.

If your security policy requires per-user authorization decisions at the application layer, raise it on the demo call. The reverse-proxy patterns below can enforce this without requiring psLens itself to grow an RBAC model.

---

## 3. SSO Today: Reverse Proxy {#sso-today-reverse-proxy}

The recommended pattern for any production deployment is to **front psLens with a reverse proxy that handles SSO**, and turn off the built-in magic-link layer. This delegates authentication to the IdP you already trust.

Common setups:

|                                Reverse proxy                                |                Identity providers                |                                   Notes                                    |
| --------------------------------------------------------------------------- | ------------------------------------------------ | -------------------------------------------------------------------------- |
| [Cloudflare Access](https://www.cloudflare.com/products/zero-trust/access/) | Okta, Azure AD, Google Workspace, OIDC, SAML     | No infrastructure for you to run; works with the fly.io-managed deployment |
| [oauth2-proxy](https://oauth2-proxy.github.io/oauth2-proxy/)                | Google, GitHub, Azure AD, Keycloak, generic OIDC | Self-hosted; sidecar to psLens                                             |
| [Pomerium](https://www.pomerium.com/)                                       | Any OIDC, SAML                                   | Self-hosted; richer policy engine                                          |
| [Tailscale](https://tailscale.com/) with serve                              | Any SSO that fronts Tailscale                    | Network-layer; locks psLens to your tailnet                                |
| Nginx / Traefik / Caddy with `forward_auth`                                 | Anything that speaks OIDC                        | Most flexible; you own the wiring                                          |

The pattern is the same in every case:

1. The reverse proxy terminates TLS, authenticates the user against your IdP, and only forwards authenticated requests to psLens.
2. psLens trusts the proxy (binds to a private network or listens on `127.0.0.1`).
3. `auth.enabled: false` in psLens config. The proxy is the identity boundary.

Cross-link: the TLS termination patterns in [Deployment Options](/docs/getting-started/deployment-options/) cover the same reverse proxies and explain how to wire them up; this page is the identity-layer companion.

**What the proxy can do that psLens RBAC could not:** enforce group membership ("only the `psoft-admins` group in Okta"), require MFA, enforce conditional access policies (managed device, geo, time-of-day), and write to your existing IdP audit log.

---

## 4. Native SSO on the Roadmap

Native OIDC support inside psLens is planned. No committed date. This will let customers who don't want a reverse-proxy hop configure their IdP directly in `config.yaml`.

We are deliberately not promising native SAML. The reverse-proxy patterns above already cover SAML; native OIDC closes the more common gap.

Until native SSO ships, reverse-proxy SSO is **production-ready**. It is the recommended deployment pattern for every customer with an enterprise IdP.

---

## 5. Session Management

|       Concern       |                                                   Behavior                                                    |
| ------------------- | ------------------------------------------------------------------------------------------------------------- |
| Where sessions live | NATS KV, bucket `auth-sessions`, scoped to this psLens instance                                               |
| Cookie scope        | HTTP-only, marked Secure when served over HTTPS                                                               |
| Idle timeout        | None today. Sessions live until the TTL expires.                                                              |
| Absolute TTL        | 1 year (configurable per deployment)                                                                          |
| Logout              | `/logout` clears the session entry from NATS KV                                                               |
| Mass invalidation   | Restart the container, or clear the `auth-sessions` bucket via `nats kv`. Useful after a credential incident. |

A built-in admin-facing "kill all sessions" UI is on the roadmap. Today the NATS CLI path above is the supported route.

---

## 6. What Reviewers Usually Ask

**"Can we require MFA?"** Yes, by fronting with a reverse proxy that enforces MFA at the IdP layer (any of the proxies above). Magic-link auth on its own is single-factor (control of the email inbox).

**"Where does the user email come from on the SWS side?"** psLens authenticates *its own users* via magic-link or reverse-proxy SSO. Those are the people using the psLens UI. psLens authenticates *to PeopleSoft* via the SWS service account (basic auth, see [Code & Supply Chain](/security/code-and-supply-chain/)). The two identity domains are independent. Your psLens users do not need PS accounts.

**"Can we revoke a user instantly?"** Yes. Remove them from `AuthorizedUsers` and restart; their next request fails. With reverse-proxy SSO, revoke them at the IdP and they lose access on the next request, no restart needed.

**"Does psLens store passwords?"** No end-user passwords. The only password-shaped secret psLens holds is the SWS service-account password used to call PeopleSoft, encrypted at rest with AES-256-GCM. See [Data Handling & Logging](/security/data-and-logging/).

---

## Related

- [Code & Supply Chain](/security/code-and-supply-chain/). What runs in the auth code path.
- [Data Handling & Logging](/security/data-and-logging/). Session storage, cookie flags, login logging.
- [Deployment & Operations](/security/deployment-and-operations/). Reverse-proxy TLS patterns that pair with reverse-proxy SSO.
