title: JSON Web Tokens Not Decodable on jwt.io: "JWT payload is not a valid JSON object"
body: <p>Using the below code, I am able to build a decoded JSON Web Token (<code>decodedToken</code>).  When I paste it into the debugger on <a href="https://jwt.io" rel="nofollow noreferrer">https://jwt.io</a>, the header and payload are correctly shown on the right.  But when I paste the encoded token (<code>encodedToken</code>) into the debugger, I get this message:</p>
  <blockquote>
  <p>Looks like your JWT payload is not a valid JSON object. JWT payloads must be top level JSON objects as per <a href="https://www.rfc-editor.org/rfc/rfc7519#section-7.2" rel="nofollow noreferrer">https://www.rfc-editor.org/rfc/rfc7519#section-7.2</a></p>
  </blockquote>
  <p>It also says, &quot;Invalid Signature,&quot; in big red letters at the bottom.</p>
  <p>In addition, when using the encoded token, the header area shows my decoded header, and the payload area shows <em>my entire decoded token</em>.  So somehow jwt.io is successfully decoding the JWT.  But it shouldn't be trying to parse the JSON of the entire decoded token as a single unit.  It should be trying to parse the JSON of the header and payload portions separately.</p>
  <p>I would like to know why jwt.io can't quite my payload of my encoded token.  The values of both the <code>decodedToken</code> and <code>encodedToken</code> are shown as comments in the below source code.  Thank you.</p>
  <pre><code>private static string GetEncodedToken(string privateKey)
  {
      JObject header = JObject.FromObject(new { alg = &quot;ES384&quot;, typ = &quot;JWT&quot; });
      JObject payload = JObject.FromObject(new { name = &quot;value&quot; });//simple test JSON data
      string decodedToken = Base64URLEncode(header) + &quot;.&quot; + Base64URLEncode(payload);
      //eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidmFsdWUifQ
      byte[] privateKeyBytes = Convert.FromBase64String(privateKey);
      using (ECDsa ecdsa = ECDsa.Create())
      {
          ecdsa.ImportECPrivateKey(privateKeyBytes, out _);
          string encodedToken = JWT.Encode(decodedToken, ecdsa, JwsAlgorithm.ES384);
          //eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.ZXlKaGJHY2lPaUpGVXpNNE5DSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnVZVzFsSWpvaWRtRnNkV1VpZlE.kYj0M2GNC5w9oRrIVcHJ9dSQLbOEjNjxd61zSXD5iz0nBRRWMWyxj2l1DAhKPa_hpaFUscuubCzYe_W1SKpo3s06on-hYnICgQH4fVoAwZxiM_N4W761jecOExfivztn
          return encodedToken;
      }
  }
  
  private static string Base64URLEncode(JObject jObject)
  {
      string jsonString = jObject.ToString(Formatting.None);
      byte[] jsonBytes = Encoding.UTF8.GetBytes(jsonString);
      string escapedBase64 = Convert.ToBase64String(jsonBytes).TrimEnd('=').Replace('+', '-').Replace('/', '_');
      return escapedBase64;
  }
  </code></pre>
  <h2>Update</h2>
  <p>Thank you for the answers so far.  I think I'm close, but jwt.io still says, &quot;Invalid Signature,&quot; even though I've pasted in the public key.  Using the below information, I'm hoping someone can tell me why my signature is said to be invalid.</p>
  <p>I've generated a temporary private key just for the purpose of debugging this situation on stackoverflow.com:
  <code>MIGkAgEBBDBywQ7LVcyOGzxJ0Tpjpww2zUZbbtb3WVm4A3uv7ho31jJzQRYTpSqR7+ORAdoxmamgBwYFK4EEACKhZANiAASG50vW1r/O1XmUbTBb6yx1YSABh1USA6MJ8HJnYJ58tjGGVPL88a6Z1gOUlAsHtNhL44PhnTNTNNFdaH2Z41yn7oZmBhuon0vuUNFic2HDpfa/uFwRUAmhSBQz8hu+980=</code></p>
  <p>I initialized an instance of <code>ecdsa</code> with my private key and generated a public key with <code>Convert.ToBase64String(ecdsa.ExportSubjectPublicKeyInfo())</code>:
  <code>MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEhudL1ta/ztV5lG0wW+ssdWEgAYdVEgOjCfByZ2CefLYxhlTy/PGumdYDlJQLB7TYS+OD4Z0zUzTRXWh9meNcp+6GZgYbqJ9L7lDRYnNhw6X2v7hcEVAJoUgUM/IbvvfN</code></p>
  <p>Here is the updated code:</p>
  <pre><code>private static string GetSignedEncodedToken(string privateKey)
  {
      JObject payload = JObject.FromObject(new { name = &quot;value&quot; });//simple test JSON data
      string payloadString = payload.ToString(Formatting.None);
      byte[] privateKeyBytes = Convert.FromBase64String(privateKey);
      using (ECDsa ecdsa = ECDsa.Create())
      {
          ecdsa.ImportECPrivateKey(privateKeyBytes, out _);
          string signedEncodedToken = JWT.Encode(payloadString, ecdsa, JwsAlgorithm.ES384);
          return signedEncodedToken;
      }
  }
  </code></pre>
  <p>And here is the signed encoded token:  <code>eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.ew0KICAibmFtZSI6ICJ2YWx1ZSINCn0.KpJAgc3-yaoGmHGAXHOeH3BPgpxdBRm461yWia60dgjuQHG5iLnwLQtQgdZtsHnI-bEK_wdmvu85ZrF7n-TdWiFb4FQxGeLBeeRfnMLJhKfInu_7MYEWPS2Ohm4yBAqg</code></p>
  <h2>Solution to Update</h2>
  <p>As mentioned by jps, I needed to wrap my public key with &quot;-----BEGIN PUBLIC KEY-----&quot; and &quot;-----END PUBLIC KEY-----&quot;.  Then jwt.io shows, &quot;Signature Verified.&quot;</p>