Firebase服务帐户生成身份验证令牌,以供客户端与Google Apps脚本一起使用
我在使用 FirebaseApp时遇到困难(第三方API)来生成身份验证令牌,该身份验证令牌可以传递到侧边栏,并由客户端用于登录和访问我的Firebase数据库客户端.
I am having difficulty using the FirebaseApp (a 3rd party API) to generate an authentication token that can be passed to a sidebar and used by the client to login and access my Firebase Database client-side.
我正在尝试使用本教程,但是如果不使用makeToken()
中的数据库机密(已贬值),就无法使其工作.我希望使用
I'm trying to use this tutorial but cannot get it working without using a database secret (which is being depreciated) in makeToken()
. I'd prefer to use a service account as reflected in this tutorial. When I look at the difference between the tokens generated, the first 2 pieces separated by a '.' are identical, the last piece after the final '.' is different. The lengths are the same as well. eg:
//Example Generated by Database Secret: TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBv.ZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=.dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2U=
//Example Generated by Service Account: TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBv.ZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=.IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbml=
我可以生成OAuth访问令牌,将其传递给FirebaseApp并生成身份验证令牌,但是当它传递给客户端并尝试进行身份验证时,会出现错误:Login Failed! Error: INVALID_TOKEN: Failed to validate MAC.
I can generate the OAuth access token, pass it to FirebaseApp and generate an authentication token, but when it is passed client-side and I attempt to authenticate I get an error: Login Failed! Error: INVALID_TOKEN: Failed to validate MAC.
关于如何执行此操作,似乎存在许多错误信息和相互矛盾的信息.
我在服务器端有一个getFirebaseService()
函数,该函数使用Apps Script OAuth2库获取访问令牌.
I have a getFirebaseService()
function server-side that uses Apps Script OAuth2 Library to get an access token.
function getFirebaseService() {
return OAuth2.createService('Firebase')
// Set the endpoint URL.
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the private key and issuer.
.setPrivateKey(fb_PRIVATE_KEY) //Service account private key
.setIssuer(fb_SERVICE_EMAIL) //Service account email
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getScriptProperties())
// Set the scopes.
.setScope('https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/firebase.database');
}
我有一个makeToken()
函数服务器端,它使用OAuth访问令牌从Firebase获取身份验证令牌.我 am 能够使用service.getAccessToken()
OAuth令牌服务器端访问和存储数据.这样行得通,我想我的问题是创建一个限制性更强的客户端身份验证令牌.
I have a makeToken()
function server-side that gets an authentication token from Firebase using the OAuth access token. I am able to use the service.getAccessToken()
OAuth token server-side to access and store data. So that works, I guess my issue is creating a client auth token that's more restrictive.
function makeToken(){
var service = getFirebaseService();
if (service.hasAccess()) {
return FirebaseApp.getDatabaseByUrl(fb_URL, service.getAccessToken()) //Database Secret Works: "AAslhfi3MYACCESSTOKEN2930hf03ah4th8" but is being depreciated.
.createAuthToken(Session.getActiveUser().getEmail());
} else {
Logger.log("makeToken: " + service.getLastError());
}
}
然后在客户端,从侧边栏,我尝试使用从makeToken()
检索到的服务器端的自定义身份验证令牌进行身份验证.
Then client-side, from the sidebar, I try to authenticate with a custom auth token retrieved server-side from makeToken()
.
var userAuthToken;
google.script.run.withSuccessHandler(function (requestAuthToken) {
userAuthToken = authenticateClient(requestAuthToken)
}).makeToken();
function authenticateClient(userRequestToken) {
var ref = new Firebase(fb_URL);
ref.authWithCustomToken(userRequestToken, function (error, authData) {
if (error) {
console.log("FB Login Failed!", error); //Error below come from here.
}
else {
console.log("FB Login Succeeded!", authData);
}
});
return ref.authData.auth;
}
结果为Login Failed! Error: INVALID_TOKEN: Failed to validate MAC.
.
Is it possible FirebaseApp is incorrectly generating the JWT Authentication Token?
Edit2 :我认为上述修改不太可能,因为我尝试使用 GSApp库,并且存在相同的问题.它似乎只想要折旧的数据库机密,而不是服务帐户OAuth.
I think the above edit is unlikely as I attempted to use the GSApp library and had the same issue. It only seems to want the depreciated database secret, not a service account OAuth.
好吧,所以经过很长的一天,我终于明白了.我将列出我最终用于库的内容以及问题所在(请参阅第三个库).主要问题是教程已过时,并且没有多少人在应用程序脚本中使用Firebase.
Alright, so after a very long day I figured it out. I'm going to lay out what I ended up using for libraries and what the issue was (see the third library). The main problem was essentially that the tutorial was outdated and no a lot of people use Firebase in apps script.
OAuth2(服务器端) 链接
我不必在这里进行任何更改!一切正常,从来没有问题.
I didn't have to change anything here! It was working fine and never an issue.
FirebaseApp(服务器端) 链接
这是一个很好的库,我坚持使用它,因为它运行良好(一旦我到那里就可以了).我必须更改来自
This is a nice library and I stuck with it because it worked well (once I got it there). I had to make a change to my original code that came from the tutorial I mentioned. My code ended up like this and worked:
if (service.hasAccess()) {
return FirebaseApp.getDatabaseByUrl(fb_URL, service.getAccessToken()) //get OAuth Token
.createAuthToken(Session.getEffectiveUser().getEmail(), null, serviceAccount.client_email, serviceAccount.private_key);
//... Added the null, private key, and service email parameters.
Firebase(客户端) 链接
好的,所以 这是我的主要问题所在 --升级代码,才能使用新的3.x版本:
Alright, so this is where my main issue was -- The tutorial I followed for client-side setup was old. I had to upgrade the code on my own to use the new 3.x version:
<script src="https://www.gstatic.com/firebasejs/5.8.2/firebase.js"></script>
// Initialize Firebase
var config = {
apiKey: "<Web API Key>",
authDomain: "<Project ID>.firebaseapp.com",
databaseURL: "https://<DB URL>.firebaseio.com/"
};
firebase.initializeApp(config);
有了这个firebase
实例,我能够更新原始的authenticateClient()
方法:
With this firebase
instance I was able to update my original authenticateClient()
method:
function authenticateClient(userRequestToken) {
firebase.auth().signInWithCustomToken(userRequestToken).catch(function(error) {
// Handle Errors here.
console.error("authClient: ", error.code, error.message);
});
return {
uid: firebase.auth().currentUser.uid,
metadata: {
lastSignInTime: firebase.auth().currentUser.lastSignInTime
}
};
}
就是这样!我现在有一个firebase
实例,该实例具有通过JWT自定义令牌登录的用户!我遇到了一些有类似问题的人,希望对您有所帮助.
That's it! I now have a firebase
instance with a signed in user via JWT Custom Token! I came across a few people with similar issues an I hope this helps.