fix(settings): API key create/delete need Outline's web session, not this app
Same limitation as Passkeys — apiKeys.create/apiKeys.delete need Outline's cookie+CSRF web session, not this app's Bearer-token auth. "New API Key…" and the per-row trash button now show an explanatory popup instead of attempting a request that doesn't work. The real create sheet, reveal-once flow, delete confirmation, and their backing functions are untouched and still fully built/tested at the OutlineKit layer — only the two trigger points were redirected, each marked with a TODO pointing back to how to re-enable them (swap the button action back) once there's a supported native auth path or Outline adds Bearer support for these two endpoints.
This commit is contained in:
@@ -53,6 +53,7 @@ struct SettingsView: View {
|
||||
@State private var didCopyRevealedKey = false
|
||||
@State private var apiKeyPendingDeletion: OutlineAPIKey?
|
||||
@State private var deletingApiKeyId: String?
|
||||
@State private var isShowingApiKeyWebOnlyNotice = false
|
||||
|
||||
/// Full Local Sync and cache-clearing both need a real connection to be
|
||||
/// safe — clearing while offline (or letting Full Local Sync think it
|
||||
@@ -772,8 +773,14 @@ struct SettingsView: View {
|
||||
Text("Personal keys")
|
||||
.font(.headline)
|
||||
Spacer()
|
||||
Button("New API Key…") { isShowingCreateApiKey = true }
|
||||
.disabled(!isEffectivelyOnline)
|
||||
// TODO: apiKeys.create needs Outline's cookie+CSRF web
|
||||
// session, not this app's Bearer-token auth — confirmed
|
||||
// this app's requests to it don't work. Swap this back to
|
||||
// `isShowingCreateApiKey = true` (the real create sheet
|
||||
// below is fully built and untouched) once there's a
|
||||
// supported native auth path, or Outline adds Bearer
|
||||
// support for this endpoint.
|
||||
Button("New API Key…") { isShowingApiKeyWebOnlyNotice = true }
|
||||
}
|
||||
.frame(maxWidth: 480)
|
||||
|
||||
@@ -807,6 +814,11 @@ struct SettingsView: View {
|
||||
Text("Any scripts or integrations using \"\(name)\" will stop working immediately.")
|
||||
}
|
||||
}
|
||||
.alert("Manage API Keys on the Web", isPresented: $isShowingApiKeyWebOnlyNotice) {
|
||||
Button("OK") {}
|
||||
} message: {
|
||||
Text("Creating and deleting personal API keys currently requires Outline's web app, the same way Passkeys does — this app can only display your existing keys for now. We may add this here in the future if Outline supports it or we add the right kind of authentication.")
|
||||
}
|
||||
}
|
||||
|
||||
/// Shown exactly once, immediately after creation — Outline never
|
||||
@@ -967,19 +979,28 @@ struct SettingsView: View {
|
||||
if deletingApiKeyId == key.id {
|
||||
ProgressView().controlSize(.small)
|
||||
} else {
|
||||
// TODO: apiKeys.delete — same web-session-only limitation
|
||||
// as create above, see that comment. Swap back to
|
||||
// `apiKeyPendingDeletion = key` (the real confirmation
|
||||
// dialog + deleteApiKey(_:) below are fully built and
|
||||
// untouched) once native auth can actually call it.
|
||||
Button {
|
||||
apiKeyPendingDeletion = key
|
||||
isShowingApiKeyWebOnlyNotice = true
|
||||
} label: {
|
||||
Image(systemName: "trash")
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.foregroundStyle(.red)
|
||||
.disabled(!isEffectivelyOnline)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 8)
|
||||
}
|
||||
|
||||
// TODO: not currently reachable from the UI — apiKeys.create needs
|
||||
// Outline's cookie+CSRF web session, confirmed this app's Bearer-token
|
||||
// requests to it don't work. Kept intact (and covered by OutlineKit
|
||||
// tests) for when native auth can support it; see the "New API Key…"
|
||||
// button's own TODO for the reconnect point.
|
||||
private func createApiKey() async {
|
||||
guard let apiClient = session.apiClient else { return }
|
||||
let trimmedName = newApiKeyName.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
@@ -1007,6 +1028,9 @@ struct SettingsView: View {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: not currently reachable from the UI — same apiKeys.delete
|
||||
// web-session-only limitation as createApiKey() above. Kept intact
|
||||
// for the same reason; see the trash button's own TODO.
|
||||
private func deleteApiKey(_ key: OutlineAPIKey) async {
|
||||
guard let apiClient = session.apiClient else { return }
|
||||
apiKeyPendingDeletion = nil
|
||||
|
||||
Reference in New Issue
Block a user