Last active
April 2, 2023 15:46
-
-
Save stuartmclean/942d488cac0d873d2c45c52850363ba9 to your computer and use it in GitHub Desktop.
Generate a self-signed JWT token for use on GCP with Typescript
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 { KJUR } from "jsrsasign"; | |
function currentTimeInSeconds(): number { | |
return Math.floor(Date.now() / 1000); | |
} | |
class Payload { | |
iss: string; | |
sub: string; | |
email: string; | |
aud: string; | |
jti: string; | |
target_audience: string; | |
exp: number; | |
iat: number; | |
constructor(clientEmail: string, targetAudience: string, ttl: number) { | |
const time = currentTimeInSeconds(); | |
this.iss = clientEmail; | |
this.sub = clientEmail; | |
this.email = clientEmail; | |
this.aud = "https://www.googleapis.com/oauth2/v4/token"; | |
this.exp = time + ttl; | |
this.jti = "jwt_nonce"; | |
this.iat = time; | |
this.target_audience = targetAudience; | |
} | |
} | |
export default class TokenProvider { | |
idToken: string; | |
ttl: number; | |
serviceAcct: string; | |
audience: string; | |
privateKey: string; | |
payload: Payload; | |
constructor(serviceAcct: string, audience: string, privateKey: string) { | |
this.ttl = 600; | |
this.idToken = ""; | |
this.serviceAcct = serviceAcct; | |
this.audience = audience; | |
this.privateKey = privateKey; | |
this.payload = new Payload(serviceAcct, audience, this.ttl); | |
} | |
async getIdToken(request: Request): Promise<string> { | |
if (this.idToken == "" || this.expired()) { | |
this.idToken = await this.generateToken(request); | |
} | |
return this.idToken; | |
} | |
private expired(): boolean { | |
return currentTimeInSeconds() + 10 >= this.ttl; | |
} | |
private async generateToken(request: Request): Promise<string> { | |
const header = { | |
alg: "RS256", | |
typ: "JWT", | |
kid: this.serviceAcct, | |
}; | |
const payload = new Payload(this.serviceAcct, this.audience, this.ttl); | |
const jwt = KJUR.jws.JWS.sign( | |
header.alg, | |
JSON.stringify(header), | |
JSON.stringify(payload), | |
this.privateKey | |
); | |
const body = | |
"grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=" + jwt; | |
const newRequestInit = { | |
method: "POST", | |
headers: { | |
Authorization: `Bearer ${jwt}`, | |
"Content-Type": "application/x-www-form-urlencoded", | |
Accept: "application/json", | |
}, | |
body: body, | |
}; | |
const url = new URL("https://www.googleapis.com/oauth2/v4/token"); | |
const newRequest = new Request(request, newRequestInit); | |
const tokenRequest = new Request(url, newRequest); | |
return await fetch(tokenRequest) | |
.then(function (response: Response) { | |
return response.text(); | |
}) | |
.then(function (text) { | |
return JSON.parse(text).id_token; | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment