{"record":{"id":"5146f11afadc3715","repo":"gotify/server","slug":"w-base64-decode-failed-w","errorCode":null,"errorMessage":"%w: base64 decode failed: %w","messagePattern":"%w: base64 decode failed: %w","errorType":"exception","errorClass":"errCannotParseToken","httpStatus":null,"severity":"error","filePath":"auth/token.go","lineNumber":124,"sourceCode":"\n// ParseEnhancedToken parses a string into an EnhancedToken.\nfunc ParseEnhancedToken(token string) (*EnhancedToken, error) {\n\ttoken, found := strings.CutPrefix(token, enhancedTokenPrefix)\n\tif !found {\n\t\treturn nil, fmt.Errorf(\"%w: token must start with %s\", errCannotParseToken, enhancedTokenPrefix)\n\t}\n\n\t// count number of dots, one dot -> ident then private key, three dots -> ident, public key, challenge then signature\n\tfields := strings.SplitN(token, \".\", 4)\n\tif len(fields) != 2 && len(fields) != 4 {\n\t\treturn nil, fmt.Errorf(\"%w: token must have 2 or 4 fields separated by dots\", errCannotParseToken)\n\t}\n\tident := fields[0]\n\tpkOrPubkeyB64 := fields[1]\n\tpkOrPubkeyBytesLen := base64.RawURLEncoding.DecodedLen(len(pkOrPubkeyB64))\n\tpkOrPubkey, err := base64.RawURLEncoding.DecodeString(pkOrPubkeyB64)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: base64 decode failed: %w\", errCannotParseToken, err)\n\t}\n\tif len(fields) == 2 {\n\t\tif pkOrPubkeyBytesLen != ed25519.SeedSize {\n\t\t\treturn nil, fmt.Errorf(\"%w: private key must be %d bytes\", errCannotParseToken, ed25519.SeedSize)\n\t\t}\n\t\treturn &EnhancedToken{\n\t\t\tident:        ident,\n\t\t\tpubOrPrivKey: pkOrPubkey,\n\t\t}, nil\n\t}\n\tif pkOrPubkeyBytesLen != ed25519.PublicKeySize {\n\t\treturn nil, fmt.Errorf(\"%w: public key must be %d bytes\", errCannotParseToken, ed25519.PublicKeySize)\n\t}\n\ttimestampStr := fields[2]\n\ttimestamp, err := strconv.ParseInt(timestampStr, 10, 64)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: timestamp must be an integer: %w\", errCannotParseToken, err)\n\t}","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/gotify/server/blob/14bfc256276775c425f988d621dccfe705de18ac/auth/token.go#L106-L142","documentation":"The key field of an enhanced token is base64 RawURL-encoded. If base64.RawURLEncoding.DecodeString fails on that segment, ParseEnhancedToken returns errCannotParseToken wrapped with \"base64 decode failed\" and the underlying decode error. It indicates the token's key segment was corrupted or never valid base64url.","triggerScenarios":"Parsing a token whose second dot-field contains characters outside the base64url alphabet (+, /, = padding, whitespace) or an impossible length — usually from copy/paste corruption, URL-encoding, or a truncated key.","commonSituations":"Tokens pasted through Markdown/HTML that re-encoded characters; shells mangling '_'/'-'; storing tokens in systems that wrap lines; manually re-encoding with standard base64 (with padding).","solutions":["Re-copy the token verbatim from its source without transformation or line-wrapping.","Ensure the key segment uses Raw URL-safe base64 (no '=' padding, '-'/'_' alphabet).","Verify the stored token wasn't URL-encoded/HTML-escaped and decode if needed.","Regenerate the token via the API if the original is unrecoverable."],"exampleFix":"// before: padded standard base64\ntok := \"gtfyident.aGVsbG8=\"\n// after: raw url-safe base64\ntok := \"gtfyident.aGVsbG8\"","handlingStrategy":"validation","validationCode":"seg := strings.Split(strings.TrimPrefix(tok, \"gtfy\"), \".\")[1]\nif _, err := base64.RawURLEncoding.DecodeString(seg); err != nil {\n    return fmt.Errorf(\"token key segment is not raw url-safe base64: %w\", err)\n}","typeGuard":"func isRawURLBase64(s string) bool {\n    _, err := base64.RawURLEncoding.DecodeString(s)\n    return err == nil\n}","tryCatchPattern":"if _, err := auth.ParseEnhancedToken(raw); err != nil {\n    if strings.Contains(err.Error(), \"base64 decode failed\") {\n        return fmt.Errorf(\"token corrupted in transit/storage: %w\", err)\n    }\n}","preventionTips":["Keep tokens out of contexts that re-encode characters (URLs, HTML, Markdown).","Use raw URL-safe base64 (no padding) when constructing key segments.","Verify token integrity after retrieval from storage or env vars."],"tags":["auth","token","base64"],"backgroundTag":"invalid-token-format","analyzedSha":"14bfc256276775c425f988d621dccfe705de18ac","analyzedAt":"2026-09-05T12:52:36.781Z","contentChangedAt":"2026-09-05T12:52:36.781Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}