Asynchronously request a signed JWT from Trello for the current member.
1 2window.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 2eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.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" }
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.
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 2const 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: