Skip to main content
All user endpoints require authentication with ROLE_USER. Users authenticate via Indy proof verification at /login/user.

Dashboard

GET /user/dashboard

Displays the user’s main dashboard with document list from Hyperledger Fabric. Authentication: Required (ROLE_USER) Response: HTML view Model Attributes:
  • displayName: User’s full name
  • idType: User’s ID type
  • idNumber: User’s ID number
  • email: User’s email
  • docs: List of documents from Fabric ledger
  • totpEnabled: Boolean indicating if TOTP is active
  • totpConfirmedAtHuman: Timestamp of TOTP confirmation
Data Source: Documents loaded from Fabric via list-docs.js script Reference: UserController.java:55

Document Viewing

Document URLs use HMAC-signed parameters to prevent unauthorized access. The SignedUrlService generates time-limited URLs for document viewing and downloading.

GET /user/docs/view/

Views a document inline (e.g., in browser or modal). Authentication: Required (ROLE_USER)
docId
string
required
Document ID from Fabric ledger
exp
Long
required
URL expiration timestamp (epoch seconds)
sig
string
required
HMAC-SHA256 signature of the URL
Response: File resource with Content-Disposition: inline Validation:
  • Document exists in Fabric for authenticated user
  • File path is within allowed directories
  • File exists and is readable
  • Signed URL is valid and not expired
Reference: UserDocsController.java:69

GET /user/docs/download/

Downloads a document as an attachment. Authentication: Required (ROLE_USER)
docId
string
required
Document ID from Fabric
exp
Long
required
URL expiration timestamp
sig
string
required
HMAC signature
Response: File resource with Content-Disposition: attachment Reference: UserDocsController.java:86
curl -X GET "https://api.example.com/user/docs/download/doc123?exp=1234567890&sig=abc123..." \
  --output document.pdf

Access Requests

GET /user/requests

Lists all access requests from issuers requesting permission to view user documents. Authentication: Required (ROLE_USER)
error
string
Optional error message to display
Response: HTML view Model Attributes:
  • requests: List of AccessRequest entities for this user
  • ccRequestsSignal: Signal string for change detection
Request States:
  • PENDIENTE: Awaiting user decision
  • APROBADA: User approved
  • RECHAZADA: User rejected
  • EXPIRADA: Expired
Reference: UserAccessRequestController.java:72

GET /user/requests/signal

Returns a lightweight signal for detecting changes in access requests. Authentication: Required (ROLE_USER) Response: JSON
ok
boolean
Success indicator
signal
string
Signal string (format: total|pending|approved|rejected|expired|maxId|maxRequestedAt|maxDecidedAt)
Usage: Frontend polling to detect new requests from issuers Reference: UserAccessRequestController.java:109

POST /user/requests//approve

Approves an access request, granting the issuer permission to view selected documents. Authentication: Required (ROLE_USER)
requestId
Long
required
Access request ID
decisionNote
string
Optional note or comment (optional)
Response: Redirect to /user/requests Validation:
  • Request must be in PENDIENTE status
  • Request must belong to the authenticated user
Effect: Changes request status to APROBADA, enables issuer document access Reference: UserAccessRequestController.java:128
curl -X POST https://api.example.com/user/requests/123/approve \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "decisionNote=Approved for verification purposes"

POST /user/requests//reject

Rejects an access request, denying the issuer permission. Authentication: Required (ROLE_USER)
requestId
Long
required
Access request ID
decisionNote
string
Optional reason for rejection
Response: Redirect to /user/requests Validation:
  • Request must be in PENDIENTE status
  • Request must belong to the authenticated user
Effect: Changes request status to RECHAZADA Reference: UserAccessRequestController.java:161

Multi-Factor Authentication (TOTP)

TOTP (Time-based One-Time Password) provides an additional security layer. Users can configure authenticator apps like Google Authenticator or Aegis.

GET /user/mfa/totp/status

Returns the current TOTP status for the authenticated user. Authentication: Required (ROLE_USER) Response: JSON
enabled
boolean
Whether TOTP is enabled
confirmedAt
string
Timestamp when TOTP was confirmed (formatted: yyyy-MM-dd HH:mm)
Reference: UserTotpController.java:63
{
  "enabled": true,
  "confirmedAt": "2024-01-15 10:30"
}

POST /user/mfa/totp/setup

Initiates TOTP setup by generating a secret and QR code URI. Authentication: Required (ROLE_USER) Response: JSON
ok
boolean
Success indicator
appName
string
Suggested authenticator apps
secret
string
Base32-encoded secret for manual entry
otpauthUri
string
URI for QR code generation (format: otpauth://totp/...)
Session: Secret stored temporarily until confirmation Reference: UserTotpController.java:75
{
  "ok": true,
  "appName": "Aegis / Google Authenticator",
  "secret": "JBSWY3DPEHPK3PXP",
  "otpauthUri": "otpauth://totp/CCDigital:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=CCDigital"
}

POST /user/mfa/totp/confirm

Confirms and activates TOTP by validating a code from the authenticator app. Authentication: Required (ROLE_USER)
code
string
required
6-digit code from authenticator app
Response: JSON
ok
boolean
Success indicator
enabled
boolean
TOTP enabled status
confirmedAt
string
Confirmation timestamp
Error Responses: 400 - Missing Code:
{
  "error": "code es requerido"
}
403 - Expired Session:
{
  "error": "La sesión de configuración TOTP expiró. Genera un nuevo código."
}
401 - Invalid Code:
{
  "error": "Código de la app inválido o expirado."
}
Reference: UserTotpController.java:98
curl -X POST https://api.example.com/user/mfa/totp/confirm \
  -H "Content-Type: application/json" \
  -d '{"code": "123456"}'

POST /user/mfa/totp/disable

Disables TOTP for the authenticated user. Authentication: Required (ROLE_USER) Response: JSON
ok
boolean
Success indicator
enabled
boolean
TOTP enabled status (false)
Effect: Removes TOTP secret and disables two-factor authentication Reference: UserTotpController.java:133

Authentication

See Authentication for detailed information on the user login flow with Indy proof verification.

Security

All user endpoints are protected by:
  • Role requirement: ROLE_USER
  • Indy proof verification: Users authenticate via verifiable credentials
  • Second factor: TOTP or email OTP required during login
  • Signed URLs: Document access uses HMAC-signed time-limited URLs
  • Path validation: Documents must be in allowed directories

Allowed Document Directories

Documents are validated to be within configured base directories: Primary: app.user-files-base-dir (env: CCDIGITAL_FS_BASE_PATH) Legacy: app.user-files-legacy-base-dir (env: APP_USER_FILES_LEGACY_BASE_DIR) Default: /home/ccdigital/CCDigitalBlock/CCDigital

Signed URL Configuration

Document viewing and download URLs use HMAC-SHA256 signatures: Format:
/user/docs/{action}/{docId}?exp={timestamp}&sig={signature}
Environment Variables:
  • APP_SECURITY_SIGNED_URLS_SECRET: Secret key for HMAC (required)
  • APP_SECURITY_SIGNED_URLS_TTL_SECONDS: URL lifetime (default: 300)
Signature Algorithm:
HMAC-SHA256(secret, path + "?exp=" + timestamp)

Session Management

These endpoints support client-side session timeout and keep-alive functionality.

GET /user/session/keepalive

Keeps the user session alive during active UI interaction. Authentication: Required (ROLE_USER) Response: 204 No Content Usage: Called periodically by frontend JavaScript to prevent session timeout during active use. Reference: SessionActivityController.java:22

GET /user/session/expire

Explicitly expires the user session due to client-detected inactivity. Authentication: Required (ROLE_USER) Response: 204 No Content Behavior:
  • Invalidates HTTP session
  • Clears Spring Security context
  • Forces user to re-authenticate
Reference: SessionActivityController.java:46

Password Recovery

Password recovery responses are intentionally generic to prevent user enumeration attacks.

POST /user/auth/forgot/verify

Initiates password recovery by sending a temporary code via email. Authentication: Not required (public endpoint) Request Body:
email
string
required
User’s registered email address
idType
string
required
ID type (CC, CE, TI, etc.)
idNumber
string
required
ID number
Response:
accepted
boolean
Whether the request was processed (true if code sent)
message
string
Generic message for UI display
Example Request:
curl -X POST https://api.example.com/user/auth/forgot/verify \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "idType": "CC",
    "idNumber": "1234567890"
  }'
Example Response:
{
  "accepted": true,
  "message": "Si los datos coinciden, se envió un código temporal al correo registrado."
}
Security: Response is generic to avoid revealing whether email/ID combination exists. Reference: ForgotPasswordController.java:51

POST /user/auth/forgot/reset

Completes password recovery by validating the temporary code and updating the password. Authentication: Not required (public endpoint) Request Body:
email
string
required
User’s email address
idType
string
required
ID type
idNumber
string
required
ID number
resetCode
string
required
Temporary code received via email
newPassword
string
required
New password (hashed with BCrypt before storage)
Response:
ok
boolean
Whether password was successfully updated
message
string
Success or error message
Example Request:
curl -X POST https://api.example.com/user/auth/forgot/reset \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "idType": "CC",
    "idNumber": "1234567890",
    "resetCode": "123456",
    "newPassword": "NewSecurePassword123!"
  }'
Example Response:
{
  "ok": true,
  "message": "Contraseña actualizada correctamente."
}
Configuration:
  • APP_SECURITY_FORGOT_PASSWORD_CODE_LENGTH: Code length (default: 6)
  • APP_SECURITY_FORGOT_PASSWORD_CODE_TTL_MINUTES: Code validity (default: 15)
  • APP_SECURITY_FORGOT_PASSWORD_MAX_ATTEMPTS: Max attempts (default: 3)
Reference: ForgotPasswordController.java:78

Build docs developers (and LLMs) love