//native
const b64url = (bytes: Uint8Array) =>
btoa(String.fromCharCode(...bytes))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "")
/**
* Get Access Token (Service Account)
* Mint a one-hour Admin SDK access token from a service account with domain-wide delegation, impersonating a Workspace admin. Returns `{ token, expires_in }`, which can be passed as the Google Workspace resource of any other script in a flow. The scopes must be authorized for the service account's client ID in Admin console > Security > API controls > Domain-wide delegation.
*/
export async function main(
service_account: RT.GcpServiceAccount,
admin_email: string,
scopes: string[] = [
"https://www.googleapis.com/auth/admin.directory.user",
"https://www.googleapis.com/auth/admin.directory.group",
"https://www.googleapis.com/auth/admin.directory.orgunit",
],
) {
const tokenUri = service_account.token_uri || "https://oauth2.googleapis.com/token"
const iat = Math.floor(Date.now() / 1000)
const enc = new TextEncoder()
const unsigned = [
{ alg: "RS256", typ: "JWT" },
{
iss: service_account.client_email,
sub: admin_email,
scope: scopes.join(" "),
aud: tokenUri,
iat,
exp: iat + 3600,
},
]
.map((part) => b64url(enc.encode(JSON.stringify(part))))
.join(".")
const pem = service_account.private_key
.replace(/\\n/g, "\n")
.replace(/-----[A-Z ]+-----/g, "")
.replace(/\s/g, "")
const key = await crypto.subtle.importKey(
"pkcs8",
Uint8Array.from(atob(pem), (c) => c.charCodeAt(0)),
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
false,
["sign"],
)
const signature = new Uint8Array(
await crypto.subtle.sign("RSASSA-PKCS1-v1_5", key, enc.encode(unsigned)),
)
const response = await fetch(tokenUri, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Accept: "application/json",
},
body: new URLSearchParams({
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
assertion: `${unsigned}.${b64url(signature)}`,
}),
})
if (!response.ok) {
throw new Error(`${response.status} ${await response.text()}`)
}
const { access_token, expires_in } = (await response.json()) as {
access_token: string
expires_in: number
}
return { token: access_token, expires_in }
}
Submitted by hugo989 1 hour ago