feat(mcp): OAuth so claude.ai and ChatGPT can connect as connectors
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m49s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m49s
MindSift becomes the OAuth authorization server for its own MCP endpoint: discovery (RFC 9728/8414), dynamic client registration, authorization code with PKCE (S256), rotating refresh tokens with reuse detection. The consent page lives in the app at /oauth/authorize. A grant is an api_keys entry (kind 'oauth'), so scopes, origin badges, renaming and revoking work as for keys; tokens are valid for /mcp only. Unused connections expire after OAUTH_IDLE_DAYS (default 90). Requires BASE_URL; off in demo mode. Release 0.51.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
994f6dc554
commit
75aea4a7d4
31 files changed
+1581
-49
No files matched your search
@@ -59,6 +59,7 @@ func (s *Store) CreateAPIKey(userID, name string, scopes []string) (*domain.APIK
|
||||
RawKey: rawKey,
|
||||
Scopes: strings.Join(NormalizeScopes(scopes), ","),
|
||||
CreatedAt: domain.NowISO(),
|
||||
Kind: APIKeyKindKey,
|
||||
}
|
||||
|
||||
_, err := s.db.Exec(
|
||||
@@ -74,7 +75,7 @@ func (s *Store) CreateAPIKey(userID, name string, scopes []string) (*domain.APIK
|
||||
|
||||
func (s *Store) GetAPIKeys(userID string) ([]domain.APIKey, error) {
|
||||
rows, err := s.db.Query(
|
||||
`SELECT id, user_id, name, key_prefix, scopes, last_used_at, created_at
|
||||
`SELECT id, user_id, name, key_prefix, scopes, last_used_at, created_at, kind
|
||||
FROM api_keys WHERE user_id = ? ORDER BY created_at DESC`,
|
||||
userID,
|
||||
)
|
||||
@@ -86,7 +87,7 @@ func (s *Store) GetAPIKeys(userID string) ([]domain.APIKey, error) {
|
||||
keys := make([]domain.APIKey, 0)
|
||||
for rows.Next() {
|
||||
var k domain.APIKey
|
||||
if err := rows.Scan(&k.ID, &k.UserID, &k.Name, &k.KeyPrefix, &k.Scopes, &k.LastUsedAt, &k.CreatedAt); err == nil {
|
||||
if err := rows.Scan(&k.ID, &k.UserID, &k.Name, &k.KeyPrefix, &k.Scopes, &k.LastUsedAt, &k.CreatedAt, &k.Kind); err == nil {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
}
|
||||
@@ -143,7 +144,7 @@ func (s *Store) ValidateAPIKeyAndGetUser(rawKey string) (*domain.User, error) {
|
||||
func (s *Store) ValidateAPIKey(rawKey string) (*domain.User, []string, string, error) {
|
||||
hash := auth.HashAPIKey(strings.TrimSpace(rawKey))
|
||||
var keyID, userID, scopes string
|
||||
err := s.db.QueryRow(`SELECT id, user_id, scopes FROM api_keys WHERE key_hash = ?`, hash).Scan(&keyID, &userID, &scopes)
|
||||
err := s.db.QueryRow(`SELECT id, user_id, scopes FROM api_keys WHERE key_hash = ? AND kind = ?`, hash, APIKeyKindKey).Scan(&keyID, &userID, &scopes)
|
||||
if err != nil {
|
||||
return nil, nil, "", errors.New("invalid API key")
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user