figma-development-kit
Version:
A set of tools that augment the Figma API
68 lines (58 loc) • 2.89 kB
JavaScript
const storageKeyForAuthorizationCodeData = 'figma-authorization-code-data';
const storageKeyForAccessTokenData = 'figma-access-token-data';
const authorizationEndpoint = 'https://www.figma.com/oauth';
const accessTokenEndpoint = 'https://www.figma.com/api/oauth/token';
export class FigmaApi {
constructor({clientId, clientSecrete, redirectUri}) {
if(!clientId) throw Error('clientId is required');
if(!clientSecrete) throw Error('clientSecrete is required');
if(!redirectUri) throw Error('redirectUri is required');
this.config = {clientId, clientSecrete, redirectUri};
}
async getOAuth2Token() {
/* if a token exists and hasn't expired, re-use it */
const existingTokenData = JSON.parse(window.localStorage.getItem(storageKeyForAccessTokenData));
if (existingTokenData && existingTokenData.expireOnEpoch > Date.now()) {
return existingTokenData.token;
}
/* if no token exists, request access code first */
const state = Math.random().toString(); // TODO randomize
const tokenPromise = this.getAuthorizationCode(state)
.then(code => this.getAccessTokenData(code))
.then(accessTokenData => this.storeAccessTokenData(accessTokenData))
.catch(error => console.error(error));
window.open(`${authorizationEndpoint}?client_id=${this.config.clientId}&redirect_uri=${this.config.redirectUri}&scope=file_read&state=${state}&response_type=code`);
return tokenPromise;
}
async getAuthorizationCode(trueState) {
return new Promise((resolve, reject) => {
let storageEventHandler = null;
window.addEventListener('storage', storageEventHandler = event => {
if (event.key === storageKeyForAuthorizationCodeData) {
const {code, state} = JSON.parse(event.newValue);
window.removeEventListener('storage', storageEventHandler);
window.localStorage.removeItem(storageKeyForAuthorizationCodeData);
if (state !== trueState) {
reject('STATE_MISMATCH');
} else {
resolve(code);
}
}
});
});
}
async getAccessTokenData(authorizationCode) {
return fetch(`${accessTokenEndpoint}?client_id=${this.config.clientId}&client_secret=${this.config.clientSecrete}&redirect_uri=${this.config.redirectUri}&code=${authorizationCode}&grant_type=authorization_code`, {
method: 'POST',
}).then(response => response.json())
.then(responseObject => {
const {access_token, expires_in} = responseObject;
const expireOnEpoch = Date.now() + expires_in * 1000;
return {token: access_token, expireOnEpoch};
});
}
storeAccessTokenData(accessTokenData) {
window.localStorage.setItem(storageKeyForAccessTokenData, JSON.stringify(accessTokenData));
return accessTokenData.token;
}
}