{"record":{"id":"b53fa7ec44f7d68f","repo":"Tencent/WeKnora","slug":"decode-oidc-state-payload-w","errorCode":null,"errorMessage":"decode oidc state payload: %w","messagePattern":"decode oidc state payload: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/utils/oidc_state.go","lineNumber":80,"sourceCode":"\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"marshal oidc state: %w\", err)\n\t}\n\tmac := hmac.New(sha256.New, []byte(oidcStateSigningKey()))\n\tmac.Write(raw)\n\tsig := mac.Sum(nil)\n\treturn base64.RawURLEncoding.EncodeToString(raw) + \".\" + base64.RawURLEncoding.EncodeToString(sig), nil\n}\n\n// VerifyOIDCState validates the HMAC and freshness of a state token.\nfunc VerifyOIDCState(raw string) (*OIDCStatePayload, error) {\n\traw = strings.TrimSpace(raw)\n\tparts := strings.Split(raw, \".\")\n\tif len(parts) != 2 {\n\t\treturn nil, errors.New(\"invalid oidc state format\")\n\t}\n\tpayloadBytes, err := base64.RawURLEncoding.DecodeString(parts[0])\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"decode oidc state payload: %w\", err)\n\t}\n\tsigBytes, err := base64.RawURLEncoding.DecodeString(parts[1])\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"decode oidc state signature: %w\", err)\n\t}\n\tmac := hmac.New(sha256.New, []byte(oidcStateSigningKey()))\n\tmac.Write(payloadBytes)\n\tif !hmac.Equal(mac.Sum(nil), sigBytes) {\n\t\treturn nil, errors.New(\"oidc state signature mismatch\")\n\t}\n\tvar payload OIDCStatePayload\n\tif err := json.Unmarshal(payloadBytes, &payload); err != nil {\n\t\treturn nil, fmt.Errorf(\"unmarshal oidc state: %w\", err)\n\t}\n\tif strings.TrimSpace(payload.RedirectURI) == \"\" {\n\t\treturn nil, errors.New(\"state.redirect_uri is required\")\n\t}\n\tif payload.IssuedAt == 0 {","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/utils/oidc_state.go#L62-L98","documentation":"VerifyOIDCState could not base64url-decode the payload segment of the signed OIDC state token. The state string must be exactly '<base64url(payload)>.<base64url(sig))>'; if the payload half is not valid base64 (Raw URL encoding, no padding), decoding fails and the error wraps the underlying reason. This is a malformed/corrupt state, not a signature failure.","triggerScenarios":"Calling VerifyOIDCState with a state value whose first dot-separated segment contains invalid base64url characters (e.g. '+' or '/' from standard base64, '=' padding, or truncation by a URL length limit or middleware).","commonSituations":"State token truncated when stored in a cookie or query parameter; double URL-encoding/decoding mangling '-' and '_'; a client constructing its own state instead of using SignOIDCState; proxy header size limits clipping the token.","solutions":["Ensure the state string is passed through URL round-trips unchanged (use URL-safe encoding end-to-end; don't re-encode the already base64url token)","Regenerate the state with SignOIDCState and confirm it matches the pattern of two dot-separated base64url segments","Check that cookies/redirects aren't truncating the value (cookie size limits, logging that clips)","Inspect the wrapped error from base64.RawURLEncoding to identify the exact offending character or length (must be a multiple of 4, unpadded)"],"exampleFix":"// before: standard base64 with padding leaks '=' into the state\nstate := base64.StdEncoding.EncodeToString(payload) + \".\" + base64.StdEncoding.EncodeToString(sig)\n// after\nstate := base64.RawURLEncoding.EncodeToString(payload) + \".\" + base64.RawURLEncoding.EncodeToString(sig)","handlingStrategy":"try-catch","validationCode":"func stateLooksWellFormed(state string) bool {\n    parts := strings.Split(state, \".\")\n    if len(parts) != 2 { return false }\n    for _, p := range parts {\n        if p == \"\" { return false }\n        if _, err := base64.RawURLEncoding.DecodeString(p); err != nil { return false }\n    }\n    return true\n}","typeGuard":"func isValidOIDCStateShape(s string) bool {\n    parts := strings.Split(s, \".\")\n    return len(parts) == 2 &&\n        base64.RawURLEncoding.EncodeToString(mustDecode(parts[0])) == parts[0]\n}","tryCatchPattern":"payload, err := utils.VerifyOIDCState(rawState)\nif err != nil {\n    if strings.Contains(err.Error(), \"decode oidc state payload\") {\n        // malformed state: restart the OIDC flow with a fresh state\n        http.Redirect(w, r, startOIDCFlow(), http.StatusFound)\n        return\n    }\n    http.Error(w, \"invalid state\", http.StatusBadRequest)\n}","preventionTips":["Always generate states with SignOIDCState; never assemble them by hand","Round-trip the state opaquely — no re-encoding, HTML escaping, or truncation","Watch cookie/redirect size limits when the payload embeds long redirect URIs"],"tags":["oidc","base64","state-token","encoding"],"backgroundTag":"oidc-state-verification-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}