diff --git a/src/DodoSSH.Client.Session/SpelunkAccounts.cs b/src/DodoSSH.Client.Session/SpelunkAccounts.cs
index 6ded166..90217e5 100644
--- a/src/DodoSSH.Client.Session/SpelunkAccounts.cs
+++ b/src/DodoSSH.Client.Session/SpelunkAccounts.cs
@@ -77,6 +77,19 @@ public sealed class SpelunkAccounts : ISpelunkAccounts
/// The longest token kept. Far beyond Spelunk's; a bound on what goes into a header and the cache.
private const int MaxTokenLength = 512;
+ /// What every token Spelunk issues a signed-in app begins with, and how Spelunk tells it from an API key.
+ ///
+ /// Checked rather than assumed: a token without it is one Spelunk would read as something else, so an answer
+ /// carrying one is not Spelunk's app sign-in, whatever else it looks like.
+ ///
+ internal const string TokenPrefix = "spelunkapp_";
+
+ /// The longest error body read, so a misbehaving proxy cannot hand this a gigabyte.
+ private const int MaxProblemBytes = 16 * 1024;
+
+ /// How long signing out waits for Spelunk before forgetting the sign-in here regardless.
+ private static readonly TimeSpan SignOutTimeout = TimeSpan.FromSeconds(10);
+
/// The page the loopback listener shows once Spelunk has sent the browser back.
private const string CompletionHtml =
"""
@@ -86,8 +99,12 @@ public sealed class SpelunkAccounts : ISpelunkAccounts