I now have enough information to give a thorough answer. Let me summarize the findings:
-
accountId rejection: The ApiKey object schema does not have an accountId field. The docs example in create.md showing --field accountId=b is inconsistent with the actual ApiKey object schema, which only accepts: description, secret (read-only/server-set), createdAt (read-only), expiresAt, permissions, and allowedIps. The required fields for creation are description and permissions.
-
Secret masked: This is by design in the CLI renderer. The source code (src/render/value.rs) explicitly renders any field typed Secret or SecretText as *****. However, the secret field is marked server-set and should be returned in the JMAP create response and displayed there – the masking is intentional for existing secrets when fetched (to protect stored credentials), but the create response should show it. This suggests a bug either in the server not returning the secret in the create response, or the CLI applying the masking even to create-time responses.
There are two distinct bugs here, both rooted in the CLI/docs:
Issue 1 – accountId is not a valid field on ApiKey
The schema reference for ApiKey lists only these writable fields: description (required), permissions (required), expiresAt, and allowedIps. There is no accountId field. An ApiKey is implicitly tied to the authenticated account that creates it – you don’t specify an account ID. The example in the create.md docs page showing --field accountId=b appears to be incorrect documentation. Use this instead:
stalwart-cli create apikey \
--field description='CI deploy key' \
--field 'permissions={"@type":"Inherit"}' \
--field 'allowedIps={}'
Issue 2 – Secret is masked even at creation time
This is a confirmed behavior issue. The CLI renderer (src/render/value.rs) unconditionally replaces any Secret-typed field value with *****, including in the create command output, which is the only time the secret is ever shown. The docs explicitly state the token is “shown only once and must be captured immediately” – but the current CLI masks it. As a workaround, you can retrieve the secret via the raw JMAP API directly:
curl -X POST https://your-server/api \
-H 'Authorization: Bearer $TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"methodCalls": [["x:ApiKey/set", {"create": {"new1": {"description": "CI deploy key", "permissions": {"@type": "Inherit"}, "allowedIps": {}}}}, "c1"]],
"using": ["urn:ietf:params:jmap:core", "urn:stalwart:jmap"]
}'
The raw JMAP response will include the secret value in plaintext in the created object, before it gets hashed and stored. This is the workaround until the CLI masking issue is resolved.
Relevant docs: ApiKey schema reference, CLI create reference
This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong. If you found it useful, mention @helpbot in any reply to ask follow-up questions and the bot will respond again.