Created
October 14, 2022 20:24
-
-
Save joshtwist/2abc51bacc2b0fd932a32261e1ed4887 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
ZuploContext, | |
ZuploRequest, | |
OpenIdJwtInboundPolicy, | |
InboundPolicyHandler, | |
OpenIdJwtInboundPolicyOptions, | |
Auth0JwtInboundPolicy, | |
Auth0JwtInboundPolicyOptions, | |
} from "@zuplo/runtime"; | |
interface JwtMapEntry { | |
name: string; | |
iss: string; | |
options: any; | |
handler: any; | |
} | |
const BEARER_PREFIX = "bearer "; | |
// This is a map of issuers to policies | |
// we're using the same policies available in the | |
// library but are using them programmatically | |
// I've done two for you :) | |
const issuerPolicyMap: JwtMapEntry[] = [ | |
// Customer Vault (Imburse Generated) | |
{ | |
name: "customer-vault-policy", | |
iss: "https://ci-vault.imburse.net/", | |
handler: OpenIdJwtInboundPolicy, | |
// These are the same options documented here: | |
// https://zuplo.com/docs/policies/open-id-jwt-auth-inbound | |
options: { | |
secret: "anders-gate-is-a-sci-fi-novel", | |
}, | |
}, | |
// Auth0 | |
{ | |
name: "auth0-policy", | |
iss: "https://dev-imbursepayments.eu.auth0.com/", | |
handler: Auth0JwtInboundPolicy, | |
// these are the same options documented here: | |
// https://zuplo.com/docs/policies/auth0-jwt-auth-inbound | |
options: { | |
auth0Domain: "https://you-fill-this-in", | |
audience: "https://you-fill-this-in/", | |
}, | |
}, | |
]; | |
const unauthorizedResponse = (message: string) => { | |
return new Response(message, { status: 401 }); | |
}; | |
export default async function (request: ZuploRequest, context: ZuploContext) { | |
// First, we're going to read the authorization header to | |
// get the JWT token - reject if none found or malformed | |
const authHeader = request.headers.get("authorization"); | |
if (!authHeader) { | |
return unauthorizedResponse(`No Authorization header`); | |
} | |
if (authHeader.toLowerCase().indexOf(BEARER_PREFIX) !== 0) { | |
return unauthorizedResponse( | |
`Invalid bearer token format for Authorization header` | |
); | |
} | |
const jwt = authHeader.substring(BEARER_PREFIX.length); | |
if (!jwt || jwt.length === 0) { | |
return unauthorizedResponse(`No JWT token on bearer`); | |
} | |
try { | |
// Next we're going to split and decode it to look at the issuer | |
const [headerEncoded, dataEncoded, signatureEncoded] = jwt.split("."); | |
const data = atob(dataEncoded); | |
const payload = JSON.parse(data); | |
// find the matching policy in our map | |
const policy = issuerPolicyMap.find((ipm) => ipm.iss === payload.iss); | |
if (!policy) { | |
return unauthorizedResponse(`Issuer '${payload.iss}' not recognized`); | |
} | |
// invoke that policy and call the result | |
return policy.handler(request, context, policy.options, policy.name); | |
} catch (err) { | |
context.log.error(err, err.toString()); | |
return unauthorizedResponse("Authentication error"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment