UNPKG

insomnia-plugin-aws-cognito-token

Version:
211 lines (200 loc) 5.35 kB
const jwtDecode = require("jwt-decode") const CryptoJS = require("crypto-js") // Get JWT Token from Cognito const session = async ({ Username, Password, Region, ClientId, TokenType, ClientSecret, }) => { const domain = Region.split('_')[0] // backward compatible with Pool const requestBody = { AuthFlow: "USER_PASSWORD_AUTH", ClientId, AuthParameters: { USERNAME: Username, PASSWORD: Password, } } if (ClientSecret) { const hash = secretHash(ClientSecret, Username, ClientId) requestBody.AuthParameters.SECRET_HASH = hash } const request = { method: "post", headers: { "content-type": "application/x-amz-json-1.1", "x-amz-target": "AWSCognitoIdentityProviderService.InitiateAuth", }, body: JSON.stringify(requestBody), } if (TokenType === 'raw_request') { return JSON.stringify(request) } const response = await fetch(`https://cognito-idp.${domain}.amazonaws.com`, request) if (response.status !== 200) { console.log( "Looks like there was a problem. Status Code: " + response.status ) return "Error in getting session: " + JSON.stringify({ request, status: response.status }) } const { AuthenticationResult } = await response.json() return AuthenticationResult ? TokenType === "id" ? AuthenticationResult.IdToken : AuthenticationResult.AccessToken : undefined } const secretHash = (ClientSecret, Username, ClientId) => ( CryptoJS.enc.Base64.stringify( CryptoJS.HmacSHA256([Username, ClientId].join(''), ClientSecret))) // Validate if the token has expired const validToken = (token) => { const now = Date.now().valueOf() / 1000 try { const data = jwtDecode(token) if (typeof data.exp !== "undefined" && data.exp < now) { return false } if (typeof data.nbf !== "undefined" && data.nbf > now) { return false } return true } catch (err) { return false } } // Encode our token const base64url = (source) => { encodedSource = CryptoJS.enc.Base64.stringify(source) encodedSource = encodedSource.replace(/=+$/, "") encodedSource = encodedSource.replace(/\+/g, "-") encodedSource = encodedSource.replace(/\//g, "_") return encodedSource } // Create a fake token to keep in store, so we don't query for same wrong values const errorToken = (error) => { const header = { alg: "HS256", typ: "JWT", } const stringifiedHeader = CryptoJS.enc.Utf8.parse(JSON.stringify(header)) const encodedHeader = base64url(stringifiedHeader) // If error we keep it for 1 min const exp = Date.now().valueOf() / 1000 + 60 const data = { error, exp, } const stringifiedData = CryptoJS.enc.Utf8.parse(JSON.stringify(data)) const encodedData = base64url(stringifiedData) return encodedHeader + "." + encodedData } // Main run function const run = async ( context, Username, Password, Region, ClientId, TokenType, ClientSecret, ) => { if (!Username) { throw new Error("Username attribute is required") } if (!Password) { throw new Error("Password attribute is required") } if (!Region) { throw new Error("Region attribute is required") } if (!ClientId) { throw new Error("ClientId attribute is required") } if (!TokenType) { TokenType = "access" } const key = [Username, Password, Region, ClientId, TokenType, ClientSecret].join("::") const token = await context.store.getItem(key) if (token && validToken(token)) { if (jwtDecode(token).error) { // Display error return jwtDecode(token).error } // JWT token is still valid, reuse it return token } else { // Compute a new token try { const token = await session({ Username, Password, Region, ClientId, TokenType, ClientSecret, }) await context.store.setItem(key, token) return token } catch (error) { // To keep thing simle we create a fake JWT token with error message const token = errorToken(error.message) await context.store.setItem(key, token) return error.message } } } module.exports.templateTags = [ { name: "AwsCognitoToken", displayName: "AWS Cognito Token", description: "Plugin for Insomnia to provide Cognito JWT token from AWS", args: [ { displayName: "Username", type: "string", validate: (arg) => (arg ? "" : "Required"), }, { displayName: "Password", type: "string", validate: (arg) => (arg ? "" : "Required"), }, { displayName: "Region", type: "string", validate: (arg) => (arg ? "" : "Required"), }, { displayName: "ClientId", type: "string", validate: (arg) => (arg ? "" : "Required"), }, { displayName: "TokenType", type: "enum", defaultValue: "access", options: [ { displayName: "access", value: "access", }, { displayName: "id", value: "id", }, { displayName: "Raw Request", value: "raw_request", }, ], }, { displayName: "ClientSecret", type: "string", }, ], run, }, ]