I had a simple node.js server that used the Firebase Admin API and the identity toolkit to generate a refresh token for a client to operate in Firebase:
The client makes a POST to our server with his credentials.
The server checks the credentials and creates a custom token with the client identifier (customToken).
var admin = require("firebase-admin");
...
admin.auth().createCustomToken(uid);
The server sends a POST request to https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key=API_KEY with the payload {"returnSecureToken": true, "token": customToken} and that returns the IdToken and the RefreshToken.
The servers return the IdToken and the RefreshToken to the client.
The client is very simple and don´t use the Firebase client SDK, and comunicates with Firebase Database with REST.(For example GET https://mydomain.firebaseio.com/x.json?auth=IdToken).
When the IdToken expires, the Client send a POST Request to https://securetoken.googleapis.com:443/v1/token?key=API_KEY with the payload {"grantType" : "refresh_token", "refreshToken": RefreshToken} and get the new IdToken.
Now I´m trying to migrate from using Identity Toolkit to Firebase Authentication and made the following changes on the server:
The client makes a POST to our server with his credentials.
The server checks the credentials and creates a custom token with the client identifier (customToken), then Sign In with the firebase client API and the custom token to get the IdToken and RefreshToken.
var firebase = require("firebase");
var admin = require("firebase-admin");
...
admin.auth().createCustomToken(uid)
.then(function (customToken) {
firebase.auth().signInWithCustomToken(customToken).then(function (usuario) {
firebase.auth().currentUser.getIdToken().then(function (IdToken) {
console.log(IdToken);
console.log(firebase.auth().currentUser.refreshToken);
...
});
}
);
}).catch(function (error) {
console.log("Error creating custom token:", error);
});
The servers return the IdToken and the RefreshToken to the client.
The client can´t use the Firebase client SDK, and comunicates with Firebase Database with REST.(For example GET https://mydomain.firebaseio.com/x.json?auth=IdToken).
When the IdToken expires, the Client send a POST Request to https://securetoken.googleapis.com:443/v1/token?key=API_KEY with the payload {"grantType" : "refresh_token", "refreshToken": RefreshToken} and get the new IdToken.
From what I understand reading the documentation, the server should only create the customTokenId and then the client, using Firebase Client SDK should sign In using that customToken, but in this case the client is so simple that don´t have the option of using the Client SDK, and only operates with REST to Firebase.
¿Is this the correct way of manage the the authentication proccess?
¿Will be Step 5 deprecated and have problems in the future?
Related
I've created a custom Firebase App Check provider for my firebase apps. My question is, how do I properly send a successful request using Firestore REST API after getting the token from my custom app check. Thanks!
You need to set the appCheck token in the headers of your request like so
// Include the App Check token with requests to your server.
const apiResponse = await fetch('https://yourFirebaseRestApiURL/Endpoint', {
headers: {
'X-Firebase-AppCheck': appCheckTokenResponse.token,
}
});
This is not documented in the Firestore Rest API but in the AppCheck docs
https://firebase.google.com/docs/app-check/web/custom-resource
I am using my spreadsheet as an admin interface for my Firebase app, where I can authorize some user transactions on the app. The spreadsheet leverages Google apps script and cloud functions
I am able to send data back and forth on the spreadsheet and my backend and now, the next thing is to lock down access to the cloud functions HTTP URL to authorized users with admin attribute in custom claims set to true.
To do this, am hoping to send the user's OAuth token gotten from Google Apps Script API (ScriptApp.getOAuthToken()) as part of the request payload and use firebase rest API method https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp?key=[API_KEY] to get the user's id token and other credentials in other to verify and authorise the admin user and the transaction.
const credentials = {
postBody: `id_token=${token}&providerId=google.com`,
requestUri: oAuthCredentials.web.redirect_uris[0],
returnIdpCredential: false,
returnSecureToken: true
}
APIRequest(IdentityUrls.signInWithOAuth, {
headers: {
'Content-Type': "application/json"
},
method: 'POST',
body: JSON.stringify(credentials)
}, (error, res) => {
...// perform actions here
})
The problem is that I keep getting INVALID_IDP_RESPONSE: The supplied auth credential is malformed or has expired. I am not sure why it's so and would appreciate help
I finally figured it out. What I am doing now is send the OAuth token as described in the question to the backend and make a POST request to token info endpoint with a payload of access_token: OAuth token. This returns a response with user email, email_verified, expiry_date etc. Then using this user email, I can get the userRecord on the Firebase Admin SDK which exposes a customClaims attribute. Read more about the solution here
I'm trying to authenticate my users using email and password from the server, using firebase and sending the token generated to the client.
In the server-side, I'm using a nodejs firebase function, and the token is created using the firebase rest auth API, using the verifyPassword endpoint, then I use the token generated and send it to the client.
I'm using in the client firebase.auth().signInWithCustomToken(token) to try to sign in, but I get me a invalid token response.
What I'm trying to do is allow to authenticate the user in both sides, the server, and WebClient
.
Is this possible or there is a better way to do it?
you can send your Client-Side idToken to your server, as described in the Firebase Auth Documentation and on your server you can create a Session-Cookie with firebase admin
admin.auth().createSessionCookie(idToken, {expiresIn})
.then((sessionCookie) => ...
I have a project where i send the idToken to the server when the Auth-State changes on my Client-Side:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
user.getIdToken().then(idToken => {
sendTokenToServer(idToken,csrfToken);
});
} else {
clearCookiesOnServer(...);
}
});
I'm trying to implement the Authorization Code Flow to link actions on google with my firebase users:
https://developers.google.com/actions/identity/oauth2-code-flow
So far I've understood the flow as follows:
1 - User access the application and is redirected to the authorization url endpoint
2 - User signs in and google receives an authorization token
3 - Google sends this authorization token to the token url endpoint and gets an access token a refresh_token and a expiration time
4 - Google sends the refresh token to get a new access token when the access token is going to expire and gets a new acess token and a new expiration time
Did I get everything right?
As authorization token and access token I'm using the custom tokens from Firebase. My question is, how can I implement the refresh token? I cannot get this token from the Firebase Node.js SDK server side.
How can I greate long-lived tokens with Firebase Node.js SDK?
Is there another approach?
Yes, you got the OAuth2 process right.
The Firebase Admin SDK lets you sign the user in to your Firebase service using generated custom tokens. Though the custom token expires within 1 hour, once user is signed-in, they should be authenticated indefinitely (i.e. until user signs out). As such, there is really no need for SDK to generate refresh token.
I'd suggest a different approach. Use Actions on Google's SignIn helper intent to get user's info, such as email, name etc. Using this info, you will be able to sign the user in to Firebase as follows (referenced from the "Create Custom Token" Firebase doc):
var uid = "some-uid";
admin.auth().createCustomToken(uid)
// token == custom token
.then(function(token) {
firebase.auth().signInWithCustomToken(token).catch(function(error)
{
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
})
.catch(function(error) {
console.log("Error creating custom token:", error);
});
References:
"How to use refresh token?" from Firebase's GitHub
"Create custom tokens" from Firebase's docs
"Request Signin helper" from Actions on Google docs
I'm currently developing a node.js service with firebase 3.0 that is called by a web application that uses firebase 2.4.
I'm sending the current user Firebase ID token (Auth.$getAuth().token) in my header call and trying to validade this token with
var idToken = req.headers["x-access-token"];
auth.verifyIdToken(idToken).then(function(decodedToken) {
var uid = decodedToken.sub;
console.log(decodedToken);
}, function(error){
console.log(error);
});
But I'm getting:
[Error: Firebase Auth ID token has no "kid" claim]
getAuth():
UPDATE
I'have just tested generating and validating the token on the server side and I'm getting the same problem.
var auth = firebase.auth();
var token = auth.createCustomToken(userId, {"premium_account": true});
console.log(token);
auth.verifyIdToken(token).then(function(decodedToken) {
console.log(decodedToken);
}, function(error){
console.log(error);
});
Any suggestions?
UPDATE 2: [SOLUTION]
The problem in my case was that the Tokens generated with AngularFire 2.X.X are not compatible with the Firebase 3.X.X that is running in my server. So after digging into some thoughts that people wrote here and in this google group topic the workaround was to use jsonwebtoken as follows:
var jwt = require('jsonwebtoken');
jwt.verify(idToken, fbKey, function(err, decoded) {
if (!err){ console.log(decoded); }
});
You can find the fbKey accessing the new firebase console and going into Settings -> Project Settings -> Database.
The documentation states that a Firebase ID Token is not the same as a Custom Token, and that verifyIdToken() is not intended for verifying tokens generated with generateCustomToken().
Old style custom tokens still seem to work (signed with a database secret instead of a service account private key). You can generate and verify these yourself using firebase-token-generator.js and/or jsonwebtoken.js.
Copied from Firebase Project > Settings > Database > Secrets
Create custom database authentication tokens using a legacy Firebase
token generator. At least one secret must exist at all times.
Seems like there is no way to use firebase's createCustomToken and verifyIdToken in a couple.
Method createCustomToken uses method sign from jsonwebtoken module which does not put "kid" claim in header section of jwt by default.
And createCustomToken does not put it itself.
I suppose at this time you can use jsonwebtoken module directly to generate token with own key id.
firebase#3.0.2
--jsonwebtoken#5.7.0
The token you pass to your server is not a JWT token, and verifyIdToken need a JWT Token.
To obtain a JWT token in your web application, run firebase.app().auth().currentUser.getToken().
Personnally I removed angularfire, the basic firebase framework made angularfire pretty useless in my opinion. Plus, a compatible version with firebase 3.0 of angularfire is not yet released, probably in the next week according to the firebase team.