Skip to content

Commit bd35195

Browse files
save file
1 parent b8e3885 commit bd35195

File tree

1 file changed

+149
-0
lines changed
  • utils/gcloud/generate-token-from-service-account-keyfile

1 file changed

+149
-0
lines changed
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
2+
3+
4+
async function generate(keyfile){
5+
6+
7+
8+
var clientEmail = keyfile.client_email;
9+
var privateKeyPem = keyfile.private_key.replace(/\\n/g,'\n');
10+
var scope = 'https://www.googleapis.com/auth/devstorage.read_write';
11+
12+
var assertion = await buildJwtAssertion({clientEmail,privateKeyPem,scope});
13+
var json = await exchangeForAccessToken(assertion);
14+
var token = json.access_token;
15+
16+
17+
return {json,token};
18+
19+
20+
21+
function base64url(input){
22+
23+
let bytes;
24+
25+
if(typeof input=='string'){
26+
bytes = encoder.encode(input);
27+
}else if(input instanceof ArrayBuffer){
28+
bytes = new Uint8Array(input);
29+
}else if(ArrayBuffer.isView(input)){
30+
bytes = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
31+
}else{
32+
throw new TypeError('Unsupported input');
33+
}
34+
35+
var bin = '';
36+
for(var i=0;i<bytes.length;i++){
37+
38+
bin += String.fromCharCode(bytes[i]);
39+
40+
}//for
41+
42+
var str = btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
43+
return str;
44+
45+
}//base64url
46+
47+
48+
function pemToArrayBuffer(pem){
49+
50+
const b64 = pem.replace(/-----BEGIN [^-]+-----/g, '')
51+
.replace(/-----END [^-]+-----/g, '')
52+
.replace(/\s+/g, '');
53+
const raw = atob(b64);
54+
const buf = new Uint8Array(raw.length);
55+
56+
for(let i=0;i<raw.length;i++){
57+
58+
buf[i] = raw.charCodeAt(i);
59+
60+
}//fpr
61+
62+
return buf.buffer;
63+
64+
}//pem_buf
65+
66+
67+
async function importPkcs8PrivateKey(pem) {
68+
69+
var keyData = pemToArrayBuffer(pem);
70+
var key = await crypto.subtle.importKey('pkcs8',keyData,{name:'RSASSA-PKCS1-v1_5',hash:'SHA-256'},false,['sign']);
71+
return key
72+
73+
}//import
74+
75+
76+
async function signRS256(privateKey, dataToSign) {
77+
78+
var dataBytes = encoder.encode(dataToSign);
79+
var sig = await crypto.subtle.sign({name:'RSASSA-PKCS1-v1_5'},privateKey,dataBytes);
80+
var uint8 = new Uint8Array(sig);
81+
return uint8;
82+
83+
}//sign
84+
85+
86+
async function buildJwtAssertion({clientEmail,privateKeyPem,scope,aud='https://oauth2.googleapis.com/token'}){
87+
88+
var key = await importPkcs8PrivateKey(privateKeyPem);
89+
90+
var now = Math.floor(Date.now()/1000);
91+
var header = {alg:'RS256',typ:'JWT'};
92+
var payload = {
93+
iss : clientEmail,
94+
scope : Array.isArray(scope) ? scope.join(' ') : scope,
95+
aud : aud,
96+
iat : now,
97+
exp : now+3600, // 1 hour max
98+
};
99+
100+
var encodedHeader = base64url(JSON.stringify(header));
101+
var encodedPayload = base64url(JSON.stringify(payload));
102+
var unsigned = `${encodedHeader}.${encodedPayload}`;
103+
104+
var sig = await signRS256(key,unsigned);
105+
var encodedSig = base64url(sig);
106+
var str = `${unsigned}.${encodedSig}`;
107+
return str
108+
109+
}//build
110+
111+
112+
async function exchangeForAccessToken(assertion) {
113+
114+
var url = 'https://oauth2.googleapis.com/token';
115+
var body = new URLSearchParams({grant_type:'urn:ietf:params:oauth:grant-type:jwt-bearer',assertion});
116+
var headers = {'Content-Type':'application/x-www-form-urlencoded'};
117+
118+
var err;
119+
try{
120+
121+
var res = await fetch(url,{method:'post',headers,body});
122+
123+
}//try
124+
catch(err2){
125+
126+
err = err2;
127+
128+
}//catch
129+
if(err){
130+
console.error(err);
131+
disp(err.toString());
132+
return;
133+
}
134+
135+
if(!res.ok){
136+
throw new Error(`Token exchange failed: ${res.status} ${res.statusText} ${await res.text()}`);
137+
}
138+
// { access_token, token_type, expires_in }
139+
var json = await res.json();
140+
return json;
141+
142+
}//exchange
143+
144+
145+
}//generate
146+
147+
148+
149+

0 commit comments

Comments
 (0)