Use when implementing authentication, handling CSRF tokens, configuring rate limiting, or integrating external clients via Login Flow v2. Prevents hardcoded credentials, missing CSRF tokens on state-changing requests, and insufficient rate limiting. Covers Login Flow v2 protocol, app passwords, CSRF token handling, rate limiting with UserRateLimit and AnonRateLimit attributes, brute force protection with throttle(), and OAuth2. Keywords: Login Flow v2, app password, CSRF, requesttoken, UserRateLimit, AnonRateLimit, throttle, OAuth2, login flow, app password, token auth, rate limiting, brute force, how to authenticate..
license
MIT
compatibility
Designed for Claude Code. Requires Nextcloud 28+.
metadata
{"author":"OpenAEC-Foundation","version":"1.0"}
nextcloud-syntax-authentication
Quick Reference
Authentication Methods
Method
Use Case
Credentials
Login Flow v2
Desktop/mobile clients
App password (obtained via flow)
App passwords
API clients, device-specific access
Username + app password
Basic Auth
Simple API calls
Username + password (or app password)
Session cookies
Browser-based requests
CSRF token required
OAuth2
Third-party integrations
Bearer token
OIDC
Enterprise SSO
Authorization: Bearer ID_TOKEN
Controller Security Defaults (No Attributes)
Security Layer
Default State
Override Attribute
Admin-only
Enforced
#[NoAdminRequired]
Authenticated
Required
#[PublicPage]
2FA completed
Required
#[NoTwoFactorRequired]
CSRF validated
Required
#[NoCSRFRequired]
Security Attributes (NC 27+)
Attribute
Effect
#[NoAdminRequired]
Allow non-admin authenticated users
#[PublicPage]
No login required
#[NoCSRFRequired]
Skip CSRF token validation
#[NoTwoFactorRequired]
Bypass 2FA requirement
#[UserRateLimit(limit: N, period: S)]
N calls per S seconds for logged-in users
#[AnonRateLimit(limit: N, period: S)]
N calls per S seconds for anonymous users
#[BruteForceProtection(action: 'name')]
Enable brute force throttling
Security-Related Events
Event
Since
Purpose
BeforeUserLoggedInEvent
v18
Pre-login hook
PostLoginEvent
v18
Post-login hook
LoginFailedEvent
v19
Failed login attempt
AnyLoginFailedEvent
v26
Any login failure (broader scope)
UserFirstTimeLoggedInEvent
v28
First-ever login
TokenInvalidatedEvent
v32
Auth token revoked
TwoFactorProviderChallengeFailed
v28
2FA failure
TwoFactorProviderChallengePassed
v28
2FA success
Critical Warnings
NEVER store user passwords in client applications -- ALWAYS use Login Flow v2 to obtain app passwords.
NEVER use #[PublicPage] + #[NoCSRFRequired] on state-changing endpoints without additional authentication -- this leaves the endpoint completely unprotected.
NEVER disable brute force protection on authentication endpoints -- attackers will exploit unthrottled login.
NEVER call $response->throttle() on success -- ALWAYS call it only on failure conditions.
NEVER poll Login Flow v2 without backoff -- ALWAYS use 1-2 second intervals between polls.
NEVER ignore the 20-minute token expiry in Login Flow v2 -- ALWAYS implement timeout handling in the client.
ALWAYS require the OCS-APIRequest: true header on OCS endpoints as CSRF alternative.
ALWAYS use #[BruteForceProtection] on endpoints that accept credentials or tokens.
ALWAYS store app passwords securely on the client -- the password is shown only once.
Decision Trees
CSRF Protection Decision Tree
Is this a browser-based form submission?
├── YES → Use requesttoken field/header
│ (default CSRF protection handles this automatically)
│
└── NO → Is this an API endpoint?
├── YES → Is it an OCS endpoint?
│ ├── YES → Require OCS-APIRequest: true header
│ │ (OCSController handles this automatically)
│ └── NO → Use #[NoCSRFRequired] + require
│ token-based auth (app password / OAuth2)
│
└── NO → Is it a public read-only endpoint?
├── YES → #[PublicPage] + #[NoCSRFRequired] is acceptable
└── NO → Keep CSRF protection enabled (default)
Authentication Attribute Decision Tree
Who needs access?
├── Admins only → No attributes needed (default)
├── Any logged-in user → #[NoAdminRequired]
├── Anonymous users → #[PublicPage]
│ └── Does it change state?
│ ├── YES → Add authentication via other means
│ │ (API key, app password, rate limiting)
│ └── NO → #[PublicPage] + #[NoCSRFRequired] is safe
└── External API clients → #[NoAdminRequired] + #[NoCSRFRequired]
└── ALWAYS require Basic Auth with app password
Rate Limiting Decision Tree
Is this a sensitive endpoint?
├── YES → Does it accept credentials?
│ ├── YES → #[BruteForceProtection(action: 'name')]
│ │ + throttle() on failure
│ └── NO → Is it resource-intensive?
│ ├── YES → #[UserRateLimit] + #[AnonRateLimit]
│ └── NO → No rate limiting needed
└── NO → Is it public?
├── YES → Consider #[AnonRateLimit] to prevent abuse
└── NO → No rate limiting needed
ALWAYS store appPassword securely. ALWAYS use loginName + appPassword for all subsequent requests.
Pattern 2: CSRF Token Handling
Browser-based requests (default -- no attributes needed):
// CSRF is validated automatically by the SecurityMiddleware#[NoAdminRequired]publicfunctionupdateItem(int$id, string$title): JSONResponse{
returnnewJSONResponse($this->service->update($id, $title));
}
<!-- Template includes requesttoken automatically --><formmethod="POST"action="..."><inputtype="hidden"name="requesttoken"value="<?php p($_['requesttoken']); ?>">
...
</form>
API clients use the OCS-APIRequest: true header as CSRF alternative: