5.5 KiB
5.5 KiB
Visione CIE Authentication Integration
Goal
Keep Visione backend simple.
Visione does not implement OIDC Federation or CIE protocol details directly.
spid-cie-oidc-django handles CIE login. Visione only manages:
- local login
state - user provisioning
- external identity linking
- local bearer token issuance
Components
- Visione backend:
POST /api/v1/auth/cie/start,POST /api/v1/auth/cie/exchange,GET /api/v1/auth/cie/session/{state} - Django RP service:
examples/relying_party - Frontend: browser redirect + polling
End-to-End Flow
- Frontend calls
POST /api/v1/auth/cie/startwithfrontend_redirect_uri. - Visione stores row in
cie_auth_sessionsand returnsauthorization_url. - Frontend redirects browser to returned Django URL.
- Django RP performs CIE login with provider.
- On success Django extracts user attributes and sends signed JSON payload to
Visione
POST /api/v1/auth/cie/exchange. - Visione verifies HMAC signature, validates
state, finds or creates user, storesuser_external_identities, issuesapi_tokens, marks session authenticated. - Visione responds to Django with HTTP redirect to
frontend_redirect_uri?state=<state>. - Frontend reads
statefrom query string and pollsGET /api/v1/auth/cie/session/{state}until authenticated. - Frontend stores returned Visione bearer token and calls
GET /api/v1/me.
Why This Architecture
- No OIDC/Federation crypto in C++ backend.
- No CIE protocol tables spread across Visione domain code.
- Django demo repo stays reusable and isolated.
- Visione keeps final auth authority for application tokens and user model.
Visione Backend Config
config.json:
"cie_auth": {
"service_base_url": "http://127.0.0.1:8001",
"start_path": "/visione/start",
"shared_secret": "change-me-for-local-dev",
"state_ttl_minutes": 10,
"default_frontend_redirect_uri": "http://localhost:3000/auth/cie/callback"
}
Meaning:
service_base_url: Django RP base URLstart_path: Django entrypoint used by frontend redirectshared_secret: HMAC secret shared only between Visione and Djangostate_ttl_minutes: local login state lifetimedefault_frontend_redirect_uri: fallback if frontend omits value
Visione DB Additions
cie_auth_sessionsstores local state, frontend redirect, final user id, final bearer tokenuser_external_identitiesstoresprovider,issuer,subject,fiscal_code, raw claims
User matching strategy:
- exact external identity on
provider + issuer + subject - fallback reunification on
fiscal_code - otherwise create new
citizen
Signed Exchange Contract
Django sends POST /api/v1/auth/cie/exchange with JSON:
{
"state": "visione-login-state",
"issuer": "http://127.0.0.1:8002/oidc/op",
"subject": "provider-subject",
"fiscal_code": "RSSMRA80A01H501U",
"first_name": "Mario",
"last_name": "Rossi",
"email": "[email protected]"
}
Headers:
Content-Type: application/jsonX-Visione-Signature: <UPPERCASE_HEX_HMAC_SHA256>
Signature algorithm:
- payload bytes exactly as sent
- key =
cie_auth.shared_secret - HMAC-SHA256
- uppercase hex output
Django Example Customization
Modified files in spid-cie-oidc-django/examples/relying_party:
relying_party/settingslocal.py.examplerelying_party/urls.pyrelying_party/visione_views.py
Added endpoints:
GET /visione/startstores Visionestatein Django session, then redirects to/oidc/rp/authorizationGET /visione/completereadsoidc_rp_user_attrs, signs payload, calls Visione exchange endpoint, then redirects browser to frontend callback URL returned by Visione
Important:
- default OIDC callback remains managed by
spid_cie_oidc.relying_party LOGIN_REDIRECT_URLnow points to/visione/complete- no need to modify RP metadata dump callback URI for this integration
Frontend Responsibilities
- Call:
POST /api/v1/auth/cie/start
Content-Type: application/json
{
"frontend_redirect_uri": "http://localhost:3000/auth/cie/callback"
}
- Redirect browser to
authorization_url. - On frontend callback page, read
statefrom query string. - Poll:
GET /api/v1/auth/cie/session/{state}
- Handle states:
pending: keep pollingauthenticated: saveauth.tokenfailed: show error and restart flow
- After token, call
GET /api/v1/me.
Frontend does not need:
- CIE secrets
- Django shared secret
- OIDC token parsing
Local Dev Setup
- Start Visione dependencies:
docker compose up -d
- Run Visione:
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug
cmake --build build
./build/visione-backend
- In separate repo checkout for
spid-cie-oidc-django, configure:
- federation authority example
- provider example
- relying party example with
VISIONE_BACKEND_EXCHANGE_URL - same
VISIONE_SHARED_SECRETas Visionecie_auth.shared_secret
- Start Django RP on
http://127.0.0.1:8001.
Security Notes
- Shared secret must never reach frontend.
cie_auth.shared_secretmust change outside local dev.- Keep
state_ttl_minutesshort. - Visione bearer token stays out of query string; only
stategoes to frontend. - Django service is trusted bridge. Protect it as internal auth component.
Future Improvements
- Mark failed sessions explicitly when Django login fails
- Rotate HMAC secret through environment variables
- Add replay protection with timestamp/nonce in signed payload
- Add integration tests between Django RP and Visione