Capabilities
Client Library
Color Theme Compliance (Beta)
UI Functions

t.jwt(opts)

Asynchronously request a signed JWT from Trello for the current member.

1
2
window.TrelloPowerUp.initialize({
  "board-buttons": async function (t, opts) {
    if (t.isMemberSignedIn()) {
      const jwt = await t.jwt({
        state: JSON.stringify({ hello: "world" }),
      });
      console.log(jwt);
    }
    return [];
  },
});

If you checked the console you would find a JWT like:

1
2
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZFBsdWdpbiI6IjVlNjY3ODRjNjA2Y2IxMTYwYThmNWRjMCIsImlkQm9hcmQiOiI1ZTY2NzgxMTYwNmNiMTE2MGE4ZjViZjciLCJpZE1lbWJlciI6IjVlNjQ1ZGMyYzQyMDVlMTQxNjIxODQwNCIsInN0YXRlIjoidGVzdCIsImlhdCI6MTU4Mzg1ODY2OCwiZXhwIjoxNTgzODU5NTY4LCJpc3MiOiJ0cmVsbG8ifQ.GubnXxnGTN0-rk3hQL_BDMDYjh-cbKldpQNWBi5aIhxqiuPyVSE9grbBjk7DSU3nn8YT3GmqgLu0SUv4K-ir53GptEfRAN1_jRrMrLj5HNosteeqeQV18qK1v_Tg0EzLpJg29JF62dfrDwG-aYsdjMKAIDbY7gyWCyv8O7xsSdzj1mwiMXS2xbhNTIIatxKq6jiRV82lIHV6iCmir0_Gj4Xg1gbMLwG8FfijDmEQTpdXm6DdMsTmm_Ep-T-rFreSSIOF6Qq9Ee03EkkjHxzCqvWGZzU-bF6EVLU5oVdPs9V0_KOBcKsaoKgMaIsSgT5C1tVC_Am6YmFTUBtSDWg0AzGLn2-4dsL_mWfylSgNBqyANeVpFISZJaGNS5Zw8-lBzN3kO_0IvVWfF3ESaCDGra3rjEfphcnNWaVafGSsh2KftlZ_LWoc6lYTcTEow19IvfLU3R3f3Ywa3Gv7-WwQt0F2Npq6E4qGyQucmjy7-u4ns8KwAzP5sej23s6G1ni2utMiqOv1EPzyusR32bVhe7Ps0aANXgFIWlJtGo8rvJeSwrnXZodJx2L3GgY5WBMP271wgvQB-kOcAkf0uIP8WzAycEd8-voYBeB28KMIQatWpRngO4c-DexG4Wr1LAt4YmbyDZzxC4mQZah4kkxsx-0IxA06UhqqETAllVjtUIQ

We can use https://jwt.io to better understand what this JWT contains.

We see the payload is:

1
2
{
  // the id of your Power-Up
  idPlugin: "5e66784c606cb1160a8f5dc0",
  // the id of the board the user is currently using your Power-Up on
  idBoard: "5e667811606cb1160a8f5bf7",
  // the id of the member currently using your Power-Up
  idMember: "5e645dc2c4205e1416218404",
  // optional Power-Up defined state, max of 2048 characters
  state: "test",
  // issued at time, in seconds
  iat: 1583858668,
  // expiration time, in seconds
  exp: 1583859568,
  // issuer
  iss: "trello"
}

Using and validating Trello JWTs

The purpose of these JWTs is for you to be able to secure the communication between your Power-Up and your server. If you need to know that a request made by your Power-Up was made on behalf of a particular Trello user, you have two main ways of accomplishing that.

  1. If you already need and are retrieving Trello OAuth tokens for members who use your Power-Up, you can send the token in requests to your server, and validate the token by making a request with it to Trello.
  2. If you don't need a Trello OAuth token (you don't need to talk to Trello's REST API), then you should use this t.jwt() method and send the resulting JWT with requests to your server.

Here we will go into more details on what you would do on your server to decode and validate the JWT.

To start we recommend checking out the recommended libraries for your programming language / environment on jwt.io.

For this example we will assume a NodeJS environment and use jsonwebtoken.

1
2
const bent = require("bent");
const jwt = require("jsonwebtoken");

const getJSON = bent("json", { "user-agent": "bent/7.1.1" });

let publicKeys;
let publicKeysExpiry;
const getPublicKeys = async () => {
  // get a fresh set if needed
  if (!publicKeys || publicKeysExpiry < Date.now()) {
    const resp = await getJSON(
      "https://api.trello.com/1/resource/jwt-public-keys"
    );
    publicKeys = resp.keys;
    // cache for 4 hours
    publicKeysExpiry = Date.now() + 14400000;
  }

  return publicKeys;
};

const decodeAndValidate = async (token) => {
  const publicKeys = await getPublicKeys();

  // the vast majority of the time, Trello will provide a single public key
  // but should Trello need to rotate our keys we may for brief periods serve
  // two public keys
  const errors = [];
  let decoded;
  for (let key of publicKeys) {
    try {
      decoded = jwt.verify(token, key);
    } catch (err) {
      errors.push(err);
    }
  }

  if (decoded) {
    // the JWT is valid, generally we should now confirm that it belongs to us
    if (decoded.idPlugin !== "YOUR-POWER-UP-ID") {
      // this JWT is from a different Power-Up, not ours
      throw new Error("Unexpected plugin");
    }
    return decoded;
  }

  // there are a variety of reasons it might not be valid
  // the JWT could be expired, or the signature could be invalid for example
  throw errors[0];
};

Ok, so how do we know Trello's public key? Trello publishes a list of our in use public keys at: https://api.trello.com/1/resource/jwt-public-keys

1
2
{
  "keys": [
    "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0RnzInoZ0WHK4eRwwlcy\nouP6kULEFjpX+zZfhKUCGGeHj+gBkgehlbAMsKoefOUGcUXmLBH6+J7tsw2s1Qqt\naNjgEwuVdeFNCuvJvbTHosMaB0XmOLHlxagPeclSeapJmIw81vyPovSXpJK/Co5l\nm0ofcXps0EzpPUajJTLCrqzRHlQiOOCnGHBUJeN6VoNBqVgcfKOWZPYCoEyfh+yp\nRzWQ/njYTPb0lLHsASKLAA8pTGegb+2WsJ/C+k6qLcyb79wl42VOx0O/1dW+WR3s\nRAxwhRadg4aR902r5ztHdrfMslHST5b1xWs5Rj23DN1bqBIpMbsWXnhyG1m8vh+p\npsb5rxZpHTW9g5qB7NlUa15zTN5OMswLyNiJR4lZsdAyWRX8HeF6V/00l1Xuz0rh\nmsYesQzlHTDVoI6SGDBShuCEoAak8wCg9gANatXBZRQ7NxBsiqx/+MIih7eihqhm\ns37G87TLNlEsYZQs1N1hb6Q2ZQDbvu/6mg9PQuGB80ZNU+6IHoX8DdHs6kayBhva\nzfWQTyskaWxTBBvRLwphlp4J9lMwSWd+SVqFyWb+1DbKcDYOkqmEF2yeh5Y1lbJR\n5zfylS7XMwvngOHxFwv7mYUTmWiDWsyFwGKB0ydqXQdumRdJ/KFXxFv5eM1HRV+J\nQs9U01Dm9Y23J4JH6ZOOeRsCAwEAAQ==\n-----END PUBLIC KEY-----"
  ]
}

This is a list so that if Trello needs to rotate our private key, we can do so without breaking your Power-Ups, as we will publish the new public key in advance of beginning to sign with its private key counterpart.

We recommend that you poll this route perhaps daily, but at most hourly, and also have logic in your application to request the latest public keys in the event of a signature verification error.

Rate this page: