Research: Janus — Roche’s OIDC/OAuth2 Identity Provider
| Field | Value |
|---|---|
| Type | Research |
| Status | Active |
| Author | xRED Dev Team |
| Created | 2026-04-07 |
| Source | code.roche.com/janus/janus , janus.pages.roche.com |
| Related SAD | SAD-001 |
| Related ADR | ADR-002 |
1. What is Janus?
Janus is an OIDC/OAuth2 Identity Provider for Roche applications. It provides a standardised authentication layer backed by existing Roche infrastructure:
Your App → Janus (Amazon Cognito) → Roche PingFederate → Roche Active DirectoryIn simple terms: Janus provides an OIDC/OAuth2 interface to Roche’s AD, by way of PingFederate. It is described as “a very thin wrapper around existing Roche infrastructure.” The user’s credentials never reach Janus or your application — PingFederate handles the actual authentication against Active Directory.
Janus’s unique value beyond standard OIDC is AWS IAM integration: after authentication,
apps can exchange the id_token for AWS STS credentials, giving every Roche employee their
own personal IAM Role.
Slack: #help-auth
2. Architecture
| Component | Role |
|---|---|
| Amazon Cognito | OIDC/OAuth2 auth server — manages app clients, issues tokens, handles flows |
| Roche PingFederate | Enterprise identity federation — verifies credentials against AD |
| Roche Active Directory | Source of truth for employee/partner identities |
| Roche CIDM | Corporate Identity Management — manages group membership and authorisation |
| Cognito Lambda Triggers | Enrich user profiles (query AD for identity info, create/update per-user IAM roles) |
3. Tokens and Lifecycle
| Token | TTL | Contents |
|---|---|---|
id_token | 1 hour | Roche user profile (username, email, name, department, cost center, manager, groups) + standard OIDC claims. Contains PII. |
access_token | 1 hour | Minimal OAuth2 claims (iss, sub, aud, exp). No PII. For authorising HTTP requests. |
refresh_token | 30 days | Used to get new id/access tokens without re-authentication. Not available for Implicit or Device flows. |
The id_token includes Roche-specific claims:
preferred_username— Roche unix IDmanager_username— manager’s unix IDdepartment,cost_centergroups— AD groups (filtered bygroupRegexin app config)
JWT schema v2 returns groups as a proper JSON array instead of a stringified array.
4. Supported OAuth2 Flows
| Flow | Use Case | AWS Access | Token Refresh |
|---|---|---|---|
| Authorization Code Grant | Most web apps with end-users | Yes | Yes |
| Authorization Code Grant + PKCE | SPAs, mobile, enhanced security (recommended) | Yes | Yes |
| Implicit Grant | Limited customisation apps (uncommon) | Yes | Yes |
| Device Authorization Grant | CLI/terminal, headless devices | Yes | Yes |
| Client Credentials | Machine-to-machine (no user context) | No | No |
5. App Client Registration (GitOps)
Integration is GitOps-based — create a YAML file in the janus/janus repo:
# app-clients/{environment}/your-app.yml
version: 2
app:
id: xred-eln-my-integration
name: My Integration
contacts:
- xred-dev@roche.com
client:
flows:
- type: authorizationCodeGrant
secret: false
scopes: [openid, profile, email]
urls:
login:
- http://localhost:8000/callback
- https://xred-eln-my-integration-api.minerva.sandbox.pcloud.roche.com/callback
logout:
- http://localhost:8000/logoutSubmit an MR to main. After merge, the CI pipeline provisions the Cognito app client
and generates credentials (Client ID and optional Client Secret).
To get commit access: self-subscribe to the CIDM group GLOJANUS_selfservice.
6. Environments
| Environment | Roche WAM Domain | Janus Domain | Use |
|---|---|---|---|
| stable (prod) | wam.roche.com | auth.gene.com | Production |
| beta (test) | wamua.roche.com | auth-tst.gene.com | UAT — recommended for dev environments |
| alpha (dev) | wamqa.roche.com | auth-dev.gene.com | Internal Janus dev only — do NOT use |
OIDC discovery: https://app.{domain}/.well-known/openid-configuration
7. AWS IAM Integration
After OIDC authentication, apps can exchange the id_token for AWS STS credentials
via the /sts endpoint:
- Every Roche employee gets their own personal IAM Role
(
arn:aws:iam::ACCOUNT:role/janus/username) - Only the authenticated employee can assume their own role
- The role has tags matching the employee’s Roche profile
- Returns
AccessKeyId,SecretKey,SessionToken,Expiration - Enables native AWS toolkit compatibility (AWS CLI, boto3, AWS Java SDK)
Authorisation is handled by AWS IAM policies defined in the app client YAML under
user.permissions, which can be conditional on CIDM group membership.
8. Token Exchange (RFC 8693)
Janus supports token exchange at POST /exchange/token:
| Exchange Type | Use Case |
|---|---|
| Janus-to-Janus | SSO between Janus apps, migrations, tiered service architectures |
| PingFederate-to-Janus | Migration path from PingFed to Janus |
Configured on the target app via an exchange block in the YAML.
9. SDKs
| SDK | Package | Language |
|---|---|---|
janus-python | janus-python (pip) | Python |
janus-nodejs | @janus/node (npm) | Node.js |
janus-js | @janus/core (npm) | JavaScript/TypeScript |
janus-angular | — | Angular |
janus-go | — | Go |
janus-r | — | R |
janus-rust | — | Rust |
Testing SDKs for SSO testing with Playwright: janus-python-playwright,
janus-js-playwright, janus-java-playwright.
SDKs are published to Roche Artifactory (VPN required) and the GitLab package registry (no VPN, needs auth token).
10. CLIs
| Tool | Install | Purpose |
|---|---|---|
janus-cli-npm | npm install -g @janus/cli | Login, logout, whoami from terminal |
janus-cli-pip | pip install | Python-based CLI |
janus-mcp | @janus/mcp | MCP server for LLM authentication (Claude Desktop, Cursor) |
After janus login, credentials are stored in ~/.janus/credentials and
~/.aws/credentials, giving native AWS toolkit access from the terminal.
11. API Endpoints
| Endpoint | Purpose |
|---|---|
/oauth2/authorize | Initiate auth flow (redirect user to login) |
/oauth2/token | Exchange auth code for tokens, refresh tokens |
/oauth2/userInfo | Get authenticated user profile |
/oauth2/revoke | Revoke tokens |
/logout | End user session |
/sts | Exchange id_token for AWS STS credentials |
/exchange/token | RFC 8693 token exchange between apps/issuers |
12. Example Integrations
Working examples exist for: JavaScript, Angular, VueJS, SvelteKit, FastAPI, Flask, Django, Spring Boot, RShiny, Go. Each has a dedicated documentation page on the Janus docs site .
13. Alternatives at Roche
| Provider | Backing | Notes |
|---|---|---|
| Janus | Cognito + PingFed + AD | Recommended. OIDC/OAuth2. AWS IAM integration. |
| Direct PingFederate | PingFed + AD | Inconsistent support, no AWS IAM, days/weeks turnaround |
| gCS AuthService | Keycloak | Supports OIDC/OAuth2 and SAML. Slack: #rise-support-authservice |
| RSI AzureAD | Azure AD | Not integrated with Roche AD, not recommended for gRED |
| DIY Cognito | Self-managed | Overhead of maintaining own infra, no cross-app SSO |
14. Relevance to xRED ELN
External Actions (Apps layer)
The xRED Apps layer uses Janus for the Roche identity leg of the dual OAuth flow (see ADR-002). When a scientist clicks an External Action in Signals:
- Browser redirects to the xRED app
- App initiates Janus OAuth (Authorization Code Grant + PKCE)
- User authenticates via Roche SSO (PingFederate)
- Janus issues
id_token+access_token - App stores tokens in ElastiCache (see ADR-003)
- The Roche
access_tokenis used as Bearer token for calls to internal systems
Machine-to-machine (Lookups, Jobs)
For backend services that need to call internal Roche APIs without user context, Janus’s Client Credentials flow provides machine-to-machine authentication. No user interaction required — the service authenticates with its Client ID and Secret.
App Registration
Each xRED integration that requires Roche authentication needs a Janus app client YAML
in the janus/janus repo. This should be part of the integration onboarding checklist.
Use the beta environment (auth-tst.gene.com) for DEV/UAT and stable
(auth.gene.com) for PROD.