Authentication Model
YAPTIDE supports two authentication methods: native Yaptide auth (username/password) and Keycloak SSO (PLGrid federation). Both issue JWT tokens stored in httpOnly cookies.
Authentication Methods
Section titled “Authentication Methods”| Method | When Used | Users |
|---|---|---|
| Yaptide Native | Development, standalone deployments | Any registered user |
| Keycloak SSO | Production, PLGrid-integrated deployments | PLGrid-federated users |
Native Authentication Flow
Section titled “Native Authentication Flow”Simple username/password registration and login. Passwords are hashed with Werkzeug’s security module.
┌──────────┐ ┌─────────┐│ UI │ │ Backend │└────┬─────┘ └────┬────┘ │ │ │ PUT /auth/register │ │ { username, password } │ │─────────────────────────────────────>│ │ │ Hash password │ │ Create YaptideUserModel │ 201 Created │ │<─────────────────────────────────────│ │ │ │ POST /auth/login │ │ { username, password } │ │─────────────────────────────────────>│ │ │ Verify password hash │ │ Generate JWT access + refresh tokens │ 200 OK │ │ Set-Cookie: access_token (httpOnly) │ │ Set-Cookie: refresh_token (httpOnly)│ │ Body: { access_exp } │ │<─────────────────────────────────────│ │ │ │ GET /auth/refresh │ │ Cookie: refresh_token │ │─────────────────────────────────────>│ │ │ Validate refresh token │ │ Generate new access token │ 200 OK │ │ Set-Cookie: access_token (httpOnly) │ │<─────────────────────────────────────│Token Lifecycle
Section titled “Token Lifecycle”| Token | Lifetime | Storage |
|---|---|---|
| Access token | 10 minutes | httpOnly cookie |
| Refresh token | 120 minutes | httpOnly cookie |
| Simulation update key | 7 days | Backend internal |
The UI auto-refreshes the access token at 1/3 of its lifetime (approximately every 3 minutes) by hitting GET /auth/refresh.
Keycloak SSO Flow
Section titled “Keycloak SSO Flow”Used for PLGrid-integrated deployments. The UI manages the Keycloak session, then exchanges the Keycloak token with the backend for a local JWT.
┌──────────┐ ┌───────────┐ ┌──────────┐│ UI │ │ Keycloak │ │ Backend │└────┬─────┘ └─────┬─────┘ └────┬─────┘ │ │ │ │ OIDC login (PKCE S256) │ │ Redirect to Keycloak │ │───────────────────>│ │ │ │ │ │ User authenticates│ │ │ (PLGrid credentials) │ │<───────────────────│ │ │ Keycloak tokens │ │ │ (access + refresh)│ │ │ │ │ │ POST /auth/keycloak │ │ Authorization: Bearer <keycloak_token>│ │───────────────────────────────────────>│ │ │ │ Validate token against │ │ Keycloak JWKS endpoint │ │ Check PLG_YAPTIDE_ACCESS │ │ Fetch SSH certificates │ │ Create/update KeycloakUser │ │ Generate local JWT │ │ │ │ 200 OK │ │ Set-Cookie: access_token (httpOnly) │ │ Set-Cookie: refresh_token (httpOnly) │ │<───────────────────────────────────────│Keycloak Configuration
Section titled “Keycloak Configuration”The UI uses keycloak-js SDK with these settings:
| Setting | Value |
|---|---|
| Flow | Standard (Authorization Code) |
| PKCE challenge | S256 |
| Silent SSO check | Enabled (silentCheckSsoRedirectUri) |
| Token refresh | Auto-refresh when <5 min remaining |
Required environment variables:
REACT_APP_KEYCLOAK_BASE_URL=https://keycloak.example.comREACT_APP_KEYCLOAK_REALM=yaptideREACT_APP_KEYCLOAK_CLIENT_ID=my-clientREACT_APP_ALT_AUTH=plgPLGrid Service Verification
Section titled “PLGrid Service Verification”When a Keycloak token arrives, the backend checks the PLG_YAPTIDE_ACCESS claim in the token. This ensures the user has been granted access to the YAPTIDE service in the PLGrid infrastructure.
The backend also:
- Fetches SSH certificates from a dedicated cert-auth service (
CERT_AUTH_URL) - Stores the certificate and private key in
KeycloakUserModel - Uses these credentials for SSH connections to HPC clusters when submitting batch jobs
Demo Mode
Section titled “Demo Mode”When REACT_APP_TARGET=demo, authentication is bypassed entirely and only in-browser Geant4 simulations are available. See Frontend Demo — Local for setup instructions.
Backend Authorization
Section titled “Backend Authorization”The @requires_auth Decorator
Section titled “The @requires_auth Decorator”All protected endpoints use the @requires_auth() decorator, which:
- Extracts the JWT access token from the
access_tokencookie - Decodes and validates the token (signature, expiry)
- Loads the
UserModelfrom the database - Injects the
userobject into the Flask request context
@requires_auth()def post(self, user: UserModel): # user is automatically injected simulation = SimulationModel(user_id=user.id, ...)User Model Hierarchy
Section titled “User Model Hierarchy”The user model uses SQLAlchemy polymorphic inheritance on the auth_provider discriminator:
UserModel (base)├── YaptideUserModel (auth_provider="yaptide")│ └── password_hash└── KeycloakUserModel (auth_provider="keycloak") ├── cert (SSH certificate) └── private_key (SSH private key)This allows the backend to transparently handle both auth methods while storing auth-specific fields only where needed.
Security Notes
Section titled “Security Notes”- All tokens are stored in httpOnly cookies — not accessible to JavaScript (
document.cookie) - CORS is configurable via
FLASK_USE_CORS(enabled for local dev withlocalhost:3000) - Nginx terminates TLS (self-signed cert for development, real cert for production)
- Passwords are hashed with Werkzeug’s
generate_password_hash(PBKDF2) - Keycloak tokens are validated against the JWKS endpoint (asymmetric signature verification)