Skip to content

feat: migrate API key storage to Obsidian's secure SecretStorage - #2

Open
jcmexdev wants to merge 1 commit into
stroiman:masterfrom
jcmexdev:feat/secure-secret-storage
Open

feat: migrate API key storage to Obsidian's secure SecretStorage#2
jcmexdev wants to merge 1 commit into
stroiman:masterfrom
jcmexdev:feat/secure-secret-storage

Conversation

@jcmexdev

Copy link
Copy Markdown

Summary

This Pull Request addresses the security limitation of storing the DEV.to API key in plain text in the plugin's data.json file. It migrates the credential storage to use Obsidian's native SecretStorage API (introduced in Obsidian v1.11.4), which integrates securely with the operating system's keychain.

This fulfills the essential feature requested in the roadmap:

"Securely handle API keys through system keychain/secure storage"

Key Changes

  1. Secure API Key Management (main.ts)

    • Configured the settings tab to use Obsidian's native SecretStorage flow via SecretComponent to let users create/select a secure vault secret.
    • Centralized key loading and validation into a getApiKey() helper method, ensuring the real API key is fetched at runtime from app.secretStorage.getSecret rather than being saved in plain text inside data.json.
    • Added a user-friendly notice warning if the API key is not configured when running publishing commands.
    • Refactored commands (map-image-files and publish-current-note) to use the new validation helper, following the DRY principle.
  2. Documentation Update (README.md)

    • Removed warning notices about unencrypted plain-text key storage.
    • Promoted secure key storage to the "Implemented features" section.
    • Cleaned up the "Desired features" roadmap since secure keychain storage is now fully implemented.
  3. Typo Correction (main.ts)

    • Corrected the settings interface name from DevPublishPluginSessings to DevPublishPluginSettings.

Verification

  • Unit Tests: Ran npm run test successfully with all 38 tests passing.
  • Production Build: Verified that the production build compiles cleanly without errors using npm run build (esbuild bundler).
  • Manual Testing: Confirmed that the secret ID reference is saved to data.json and the actual key is retrieved securely through the Obsidian app.

@claremacrae

Copy link
Copy Markdown

I would have thought that the Obsidian version in package.json would need to be updated in order for the secret storage API to be found?

@claremacrae

Copy link
Copy Markdown

I would have thought that the Obsidian version in package.json would need to be updated in order for the secret storage API to be found?

Ah no, this probably came from the Sample Plugin, which just uses Obsidian latest.

So the minAppVersion would need to be updated if a release were to be done - in manifest.json and versions.json when a release is done...

But that would all depend on on if @stroiman were still supporting this plugin...

@stroiman

stroiman commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Hey, thanks for providing this suggestion. I didn't see this until now, but I'll check it out.

Comment thread main.ts
import Publisher from "src/publisher";

interface DevPublishPluginSessings {
interface DevPublishPluginSettings {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice to fix the typo, but it appears to me this type doesn't have any relevance anymore?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed the typo because the type is still relevant to store the secret identifier chosen by the user.

Since the user picks or creates their own secret key from the vault, we can't hardcode a default. We must save this custom key ID in settings.apiKey so we know which secret to retrieve from Obsidian's secure storage (SecretStorage).

Let me know if you see a better way to handle this, or if this approach looks good to you!

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, thanks for the feedback - I was just quickly glancing through the changes, when it caught my eye. I'll give it a more detailed look when I have time.

Comment thread main.ts
@@ -107,17 +121,16 @@ class DevPublishSettingTab extends PluginSettingTab {
.setName("API key")
.setDesc(
sanitizeHTMLToDom(

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sanitize no longer necessary.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally makes sense! I forgot to remove the sanitizer when I simplified the text. I'll update it to just use the plain string.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants