Where is my API key, and is it safe?
Pointer uses personal API keys to authenticate local CLI commands, AI editor extensions, and automated pipelines. This page explains key formats, where to manage your key, how it is secured at rest, and operational rules for self-hosters.
Finding and viewing your key
Every active user account in Pointer is assigned a personal API key. To find it:
- Sign in to the Pointer web dashboard.
- Click your user avatar in the top-right navigation bar and select Profile.
- Scroll down to the API Key section.
- Click Copy to copy the key to your clipboard.
Unlike systems that show keys only once upon creation, Pointer keys remain re-viewable on your profile page at any time. You can return whenever you need to copy it for a new dev machine or tool.
Key format & regeneration
A Pointer API key consists of the prefix ptr_ followed by 40 hexadecimal characters (representing 20 cryptographically secure random bytes), for example:
ptr_9f83a2d4e7b1056c82d41fa90e38bc7412f864e2
Regenerating your key
If your key is compromised or needs to be refreshed, click Regenerate in the Profile view.
Regenerating a key immediately revokes the old one. The old key is stamped with RevokedAt in the database and rejected on every subsequent call. Any local CLI instances, active IDE sessions, or CI workflows using the old key will fail immediately with an authentication error until updated.
Security architecture: Hashed for lookup, encrypted for display
Pointer enforces a dual-layer security model for API keys to separate authentication verification from key display:
-
Hashed for lookup (SHA-256): When you authenticate via the CLI or automated tools (
POST /api/auth/login-with-key), the server computes the SHA-256 hash of your supplied key and queries the database for an active match. The server never compares plaintext keys in SQL queries. -
Encrypted for display (AES-256-GCM): To allow you to re-view your key on the profile page, the server encrypts the key using authenticated AES-256-GCM with a dedicated server-side encryption key (
Auth:ApiKeyEncryptionKey) and stores the ciphertext alongside an initialization vector (nonce).
The database alone does not yield a usable key. An attacker who gains full unauthorized read access to the database sees only SHA-256 hashes and AES-256-GCM encrypted blobs. Because the decryption key is kept in server application configuration rather than in the database, the attacker cannot reverse the hashes or decrypt the keys without also compromising the server's runtime environment.
Local key hygiene
-
Saved in
.pointer/credentials.env: When runningnpx -y pointer-feedback init, the CLI writes your key to.pointer/credentials.env. -
Restricted file permissions: The CLI creates this file with
0600permissions (readable and writable only by your local operating system user). -
Gitignored by default: The CLI automatically writes entries into your root
.gitignoreto ensure.pointer/credentials.envis never tracked by git.
Never commit .pointer/credentials.env or hard-code ptr_ tokens in source files or docker images. If you suspect an API key was committed to version control, regenerate it immediately from your profile page.
Self-hosting & operator configuration
If you self-host the Pointer API backend, follow these configuration guidelines for API key security:
Configuring the encryption key
Before booting your Pointer instance for the first time, generate a dedicated 32-byte base64 encryption key:
openssl rand -base64 32
Set this key in your server environment variables or appsettings.json:
Auth__ApiKeyEncryptionKey="<generated-base64-key>"
The derived fallback
If Auth:ApiKeyEncryptionKey is omitted on startup, Pointer derives an encryption key from JWT:SigningKey using HKDF-SHA256 and logs a warning. While this enables zero-configuration local development, it is strongly discouraged in production because it couples two distinct security mechanisms (a leak of the JWT signing key compromises key display encryption as well).
What happens when rotating the encryption key?
If you rotate or alter Auth:ApiKeyEncryptionKey on an existing backend:
-
Key display is disabled for existing keys: When users visit their Profile page,
GET /api/me/api-keycan no longer decrypt the existing ciphertext and returnsKey display unavailable — the encryption key changed. Regenerate to get a new key.. -
Logins continue working: Because authentication verifies the SHA-256 hash in the database, existing keys stored in local
credentials.envfiles and CI pipelines remain fully functional. - Restoring display: Users simply click Regenerate in their profile to mint a new key encrypted with the updated configuration.
Scoped API keys (such as read-only keys, project-restricted tokens, or time-limited tokens) and multiple simultaneous keys per user are not yet supported. Each user account has exactly one active personal API key with permissions reflecting their account role.