gnexus-creds is a personal secret storage service with a REST API, MCP server, and web UI. The service stores only personal user data. Team, organization, and secret sharing features are out of scope for the MVP.
The service is implemented in Python with FastAPI. The frontend is implemented with Vue.js and gnexus-ui-kit.
gnexus-auth-client-py must be used as a backend dependency, not copied into this repository. The integration must rely on its public API only.
gnexus-ui-kit must be used as a frontend dependency, not copied into this repository. The UI must rely on public exported Vue components/styles only.
Both dependencies should be version-pinned through lock files while keeping a clear upgrade path through the normal package manager flow.
Expected dependency forms:
gnexus-gauth @ git+https://git.gnexus.space/git/root/gnexus-auth-client-py.git
{
"gnexus-ui-kit": "git+https://git.gnexus.space/git/root/gnexus-ui-kit.git"
}
The main domain entity is secret.
A secret has fixed metadata and a variable list of fields. Fixed metadata:
titlepurposecategorytagssourcenotesstatusarchivednotes is limited to 140 characters.
status has two values:
actualoutdatedarchived hides a secret from ordinary lists. Archived secrets are never available through MCP.
Each secret has one category. Category is a plain text field. Tags are separate search keywords.
Secret contents are represented as a variable-length list of fields:
{
"name": "password",
"value": "...",
"encrypted": true,
"masked": true,
"position": 2
}
There are no built-in templates. A secret can represent a login/password pair, API token, SSH key, card PIN, server credentials, or any other structured text data.
Field rules:
name is the field label.value is the field value.encrypted=true means the value is encrypted at rest and is not searchable.masked=true means the value is hidden by default in UI/API responses.position controls display order.Metadata, tags, category, field names, and values of fields with encrypted=false are searchable. Values of fields with encrypted=true are not searchable.
Secret versioning is required.
A new version is created when any of the following changes:
encrypted flagmasked flagMetadata updates do not create a new version. Metadata includes:
titlepurposecategorytagssourcenotesstatusarchivedOld versions are available for viewing and reveal. Revealing an old version must create an audit event.
There is no dedicated rollback operation. If a user wants to restore old values, they update the secret normally, creating a new version.
The actual / outdated status belongs to the whole secret, not to individual versions.
Access is configured globally per secret, not per field.
Flags:
allow_uiallow_rest_apiallow_mcpFor MCP reveal, both conditions are required:
reveal scope.allow_mcp=true.The REST API is JSON-only and versioned under /api/v1.
List and search endpoints return metadata plus non-encrypted fields. Full field values are returned only by reveal endpoints.
Pagination uses offset and limit.
The OpenAPI schema is a public contract and must include clear schemas, descriptions, and examples.
Errors use a stable envelope:
{
"error": {
"code": "secret_not_found",
"message": "Secret not found",
"details": {}
}
}
Required REST surface:
GET /api/v1/me
GET /api/v1/secrets
POST /api/v1/secrets
GET /api/v1/secrets/{id}
PATCH /api/v1/secrets/{id}
DELETE /api/v1/secrets/{id}
POST /api/v1/secrets/{id}/reveal
GET /api/v1/secrets/{id}/versions
GET /api/v1/secrets/{id}/versions/{version_id}
POST /api/v1/secrets/{id}/versions/{version_id}/reveal
GET /api/v1/categories
GET /api/v1/tags
GET /api/v1/suggestions
GET /api/v1/audit-events
GET /api/v1/secrets/{id}/audit-events
GET /api/v1/api-tokens
POST /api/v1/api-tokens
DELETE /api/v1/api-tokens/{id}
POST /api/v1/export
POST /api/v1/import
DELETE /api/v1/account-data
External clients use gnexus-creds API tokens. gnexus-auth is used for user login, not as the long-term token source for third-party clients.
API token rules:
Scopes:
readrevealwriteadminmcpMCP is part of the same FastAPI application. The first supported transport is HTTP/SSE. stdio is out of scope because the AI agent and MCP server are expected to run on different servers.
MCP uses the same API token model with the additional mcp scope.
MCP tools:
search_secretsget_secretreveal_secretcreate_secretupdate_secretset_secret_statusarchive_secretArchived secrets are never available through MCP.
MCP search without reveal is not audited. MCP reveal and write operations are audited with channel=mcp.
User login goes through gnexus-auth OAuth authorization code flow with PKCE. gnexus-creds acts as the backend/BFF for its UI:
gnexus-auth;gnexus-auth-client-py;/oauth/userinfo;UI requests use the server-side session cookie.
Third-party REST and MCP clients use gnexus-creds API tokens.
gnexus-auth is the source of truth for user profile data. Local user data is a cache/mapping.
Local user fields:
idauth_subjectemaildisplay_namestatuscreated_atlast_seen_atProfile/status changes are received through gnexus-auth webhooks.
If a user is deleted or blocked in gnexus-auth, login is blocked, local data is preserved, and the local user is marked disabled.
Roles come from gnexus-auth. MVP roles:
useradminAdmin UI and admin API access must be enforced on the backend.
The service master key is provided through an environment variable.
Each user gets a separate user encryption key on first login. The user key is encrypted by the master key and stored in the database.
User key rotation is out of scope for MVP.
Only values of fields with encrypted=true are encrypted. Metadata, tags, category, field names, and non-encrypted field values are stored in plaintext.
The crypto implementation should store enough metadata for future key handling, including key id, nonce, ciphertext, and algorithm.
Audit is required.
Events to log:
Search/list events are not audited. MCP search without reveal is not audited.
Failed access attempts must be rate-limited or aggregated so repeated identical bot traffic does not flood the audit log. At minimum, only the first repeated event in a suppression window should be stored.
Audit event data:
ui, rest, or mcpSecret values must never be stored in audit events.
Audit is available:
Audit retention is 1 year. Users cannot edit or clear audit logs.
Users can export all their data in the service's own JSON format. Export includes decrypted field values.
Export is a high-risk operation and must require explicit confirmation in UI. It must create an audit event.
Import supports only JSON files created by gnexus-creds export. CSV and third-party import formats are out of scope.
Secret deletion is hard delete. Secret versions are deleted with the secret. Audit events remain and must include enough snapshot data to remain meaningful.
Users can delete all their own gnexus-creds data. Dangerous actions require a confirmation modal in UI.
The UI is implemented with Vue.js and gnexus-ui-kit.
Required screens:
The main screen after login is dashboard/overview plus search.
Secret list columns:
The list may show non-encrypted fields.
Creating a secret uses one form. Required/important fields appear first. Optional fields appear below.
Reveal behavior:
Encrypted fields display the field name and reveal/copy buttons.
Categories and tags use text input with autocomplete from existing values.
Bulk actions are out of scope for MVP.
Localization is required, but MVP ships only English. User locale should be read from gnexus-auth when available.
Accessibility requirements:
Admin features are based on roles from gnexus-auth.
Admin capabilities:
Admins must not get access to decrypted user secrets by default.
Production domain:
https://creds.gnexus.spaceAuth domains:
https://auth.gnexus.spacehttp://gnexus-auth.localRuntime choices:
/health and /readyDocker is not required at the beginning of development. The project must be containerized before production deployment.
Backup and restore are outside the application scope.