Skip to content

Instantly share code, notes, and snippets.

@stuartmclean
Last active April 2, 2023 15:46
Show Gist options
  • Save stuartmclean/942d488cac0d873d2c45c52850363ba9 to your computer and use it in GitHub Desktop.
Save stuartmclean/942d488cac0d873d2c45c52850363ba9 to your computer and use it in GitHub Desktop.
Generate a self-signed JWT token for use on GCP with Typescript
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