Files
mnemosyne/mnemosyne/mcp_server/templates/mcp_server/tokens/edit.html
Robert Helewka 81426327bf feat(mcp): store MCP tokens as SHA-256 hashes instead of plaintext
Replace plaintext token storage with SHA-256 hashes so leaked database
contents cannot be used to authenticate. Plaintext is generated, shown
once at creation time, and never persisted.

- Add `hash_token()` helper and `MCPTokenManager.create_token()` that
  returns `(instance, plaintext)`.
- Replace `token` field with indexed `token_hash`; look up bearers by
  hashing the incoming value.
- Update dashboard, management command, and admin to surface plaintext
  only at creation. Disable admin "add" since it cannot reveal plaintext.
- Migration drops the old `token` column and adds `token_hash`;
  pre-existing tokens are invalidated and must be reissued.
2026-04-27 09:01:36 -04:00

61 lines
2.3 KiB
HTML

{% extends "themis/base.html" %}
{% block title %}Edit {{ token.name }} — {{ themis_app_name }}{% endblock %}
{% block content %}
<div class="max-w-2xl mx-auto">
<h1 class="text-2xl font-bold mb-6">Edit Token: {{ token.name }}</h1>
<div class="alert alert-info mb-6">
<span>You can edit metadata below. The token value itself cannot be changed — generate a new token if needed.</span>
</div>
<form method="post" action="{% url 'mcp_server:mcp-token-edit' pk=token.pk %}">
{% csrf_token %}
<div class="card bg-base-200 mb-6">
<div class="card-body">
<div class="form-control">
<label class="label" for="id_name">
<span class="label-text">Name</span>
</label>
{{ form.name }}
</div>
<div class="form-control mt-4">
<label class="label cursor-pointer justify-start gap-3">
{{ form.is_active }}
<span class="label-text">Active</span>
</label>
</div>
<div class="form-control mt-4">
<label class="label" for="id_expires_at">
<span class="label-text">Expires at (optional)</span>
</label>
{{ form.expires_at }}
</div>
</div>
</div>
<div class="card bg-base-200 mb-6">
<div class="card-body">
<h2 class="card-title text-lg">Allowed Tools</h2>
<p class="text-sm opacity-60 mb-2">{{ form.allowed_tools.help_text }}</p>
<div class="space-y-1">
{% for choice in form.allowed_tools %}
<label class="label cursor-pointer justify-start gap-3">
{{ choice.tag }}
<span class="label-text font-mono">{{ choice.choice_label }}</span>
</label>
{% endfor %}
</div>
</div>
</div>
<div class="flex justify-between">
<a href="{% url 'mcp_server:mcp-token-detail' pk=token.pk %}" class="btn btn-ghost">Cancel</a>
<button type="submit" class="btn btn-primary">Save Changes</button>
</div>
</form>
</div>
{% endblock %}