{"record":{"id":"afa358d4e85a5f62","repo":"clockworklabs/SpacetimeDB","slug":"issuer-too-long","errorCode":null,"errorMessage":"Issuer too long: {:?}","messagePattern":"Issuer too long: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/auth/src/identity.rs","lineNumber":103,"sourceCode":"\n    /// The unix timestamp the token was issued at\n    #[serde_as(as = \"serde_with::TimestampSeconds\")]\n    pub iat: SystemTime,\n    #[serde_as(as = \"Option<serde_with::TimestampSeconds>\")]\n    pub exp: Option<SystemTime>,\n\n    /// All remaining claims from the JWT payload\n    #[serde(flatten)]\n    pub extra: Option<HashMap<Box<str>, serde_json::Value>>,\n}\n\nimpl TryInto<SpacetimeIdentityClaims> for IncomingClaims {\n    type Error = anyhow::Error;\n\n    fn try_into(self) -> anyhow::Result<SpacetimeIdentityClaims> {\n        // The issuer and subject must be less than 128 bytes.\n        if self.issuer.len() > 128 {\n            return Err(anyhow::anyhow!(\"Issuer too long: {:?}\", self.issuer));\n        }\n        if self.subject.len() > 128 {\n            return Err(anyhow::anyhow!(\"Subject too long: {:?}\", self.subject));\n        }\n        // The issuer and subject must be non-empty.\n        if self.issuer.is_empty() {\n            return Err(anyhow::anyhow!(\"Issuer empty\"));\n        }\n        if self.subject.is_empty() {\n            return Err(anyhow::anyhow!(\"Subject empty\"));\n        }\n\n        let computed_identity = Identity::from_claims(&self.issuer, &self.subject);\n        // If an identity is provided, it must match the computed identity.\n        if let Some(token_identity) = self.identity\n            && token_identity != computed_identity\n        {\n            return Err(anyhow::anyhow!(","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/auth/src/identity.rs#L85-L121","documentation":"When converting incoming JWT claims into SpacetimeIdentityClaims (crates/auth/src/identity.rs:103), SpacetimeDB requires the iss claim to be at most 128 bytes. The identity is derived by hashing iss+sub into a fixed-size Identity, so oversized issuers are rejected outright.","triggerScenarios":"Authenticating with a token whose iss claim exceeds 128 bytes — e.g. a long OIDC issuer URL with paths, ports, and query strings — during token exchange / spacetime login against a custom identity provider.","commonSituations":"Custom JWT providers (Auth0, Keycloak, self-hosted) configured with verbose issuer URLs; tokens minted by internal tooling that stuffs parameters into iss; issuer URLs that grew when moving environments or regions.","solutions":["Shorten the issuer string to 128 bytes or fewer (compact identifier or bare URL without query parameters)","Reconfigure the identity provider to emit the short form of its issuer","If you mint tokens yourself, keep iss minimal and put extra metadata in custom claims"],"exampleFix":"// before (JWT payload)\n{ \"iss\": \"https://identity.internal.example.com/realms/master/protocol/openid-connect/?env=prod\", ... }\n\n// after\n{ \"iss\": \"https://identity.example.com/master\", ... }","handlingStrategy":"validation","validationCode":"// Before sending a token to SpacetimeDB, check iss:\nfunction assertIssuerOk(jwt: { iss: string }) {\n  const bytes = new TextEncoder().encode(jwt.iss).length;\n  if (bytes === 0) throw new Error('iss must be non-empty');\n  if (bytes > 128) throw new Error(`iss is ${bytes} bytes; max is 128`);\n}","typeGuard":"function hasValidSpacetimeIssuer(claims: Record<string, unknown>): claims is { iss: string } {\n  const iss = claims.iss;\n  return typeof iss === 'string' && iss.length > 0 && iss.length <= 128;\n}","tryCatchPattern":null,"preventionTips":["Keep issuer identifiers short and stable from day one","Validate iss length in your token-minting tests","Never put environment metadata or query strings in iss"],"tags":["auth","jwt","identity","claims","validation","spacetimedb"],"backgroundTag":"jwt-issuer-too-long","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}