Method Creating custom tokens will create uid if not exist in firebase - node.js

I using firebase. I using method: Creating custom tokens. When i look document in firebase https://cloud.google.com/identity-platform/docs/admin/create-custom-tokens .
const uid = 'some-uid';
admin
.auth()
.createCustomToken(uid)
.then((customToken) => {
// Send token back to client
})
.catch((error) => {
console.log('Error creating custom token:', error);
});
I have a question
If i don't have uid in firebase, it will create it ? If i have uid, i only create custom token and send back to client. I look document and i don't see document specific it. Thanks

There is no need to make an API call to create a user in Firebase when you're using custom authentication. Calling createCustomToken on the server, and then signing on the client with the resulting ID token, is all that is needed.
There is no separate step to create the UID for a custom provider. You create the custom token with the UID and other claims you want, send it to the client over a secure connection, and the client can then sign in to Firebase with that token.
For Firebase services the ID token, and the UID in it, are ephemeral - since it is your server (where you run the Admin SDK), and the client that maintain them. That's the reason a separate step to create the UID in Firebase is not necessary.

Related

how to store sub account auth tokens twilio

I am using the MERN stack for an app im building. In this app im using twilio. I have decided to use twilio sub-accounts. The way this works is I create a MASTER twilio account that give me an accountSid and authToken.
I can store these as ENV variables in Heroku when I want to deploy, and anytime I need to access these ENV vars I can just use the process.env.AUTH_TOKEN in my Node.js server.
Every customer that signs up for my app is going have their own subaccount that is a child of my MASTER account. When this sub account is created, It will give that user their own accountSid and authToken.
This is where my issue stands, Do I need to store each users authToken on Heroku as an ENV variable?
ex..
process.env.USER_1_AUTH_TOKEN
process.env.USER_2_AUTH_TOKEN
process.env.USER_3_AUTH_TOKEN
process.env.USER_4_AUTH_TOKEN
process.env.USER_5_AUTH_TOKEN
I dont think this will work because how will I know which users auth token belongs to them?
Currently in Development I am storing the sub-account authToken directly on the user object, this user object is visible to the client side of the app and im worried that exposing the auth token directly to the client could result in some sort of hack?
Is it safe to store the auth token on the user object directly in mongodb and whenever my react app needs the user, just send the user object without the auth token?
Should I create a auth-token Model, and store a document in the auth-token model containing the auth-token and user_id and everytime I need the auth token just query mongodb for the auth-token with user_id as a parameter?
How does one go about storing say 100,000 of these auth-tokens?
I'm worried about security and twilio docs dont say much about this...
According to the Subaccounts API documentation you can use the Twilio rest API to instantiate a subaccount and assign that subaccount a friendly name that is easy to retrieve.
client.api.v2010.accounts
.create({friendlyName: 'Submarine'})
.then(account => console.log(account.sid));
This returns an object that contains a lot of information but it has a unique SID for that is associated to that new number/subaccount. That object is then also linked back to your main account via the owner_account_sid which is attached to that object.
Twilio provides functionality in the subaccount API to allow you to retrieve a subaccounts data based on the friendly name like so...
client.api.v2010.accounts
.list({friendlyName: 'MySubaccount', limit: 20})
.then(accounts => accounts.forEach(a => console.log(a.sid)));
So what you should be doing is as follows...
Create a naming convention within your system that can be used to form friendly names to assign to subaccounts.
Use the API to create a new subaccount with the Twilio API under the friendly naming convention you've developed.
Anytime you want to make a call, text, or other supported action from the Twilio API first perform an API action to look up the SID of that account by the friendly name.
Grab the sid the friendly name returns and attach it to your client object like so require('twilio')(accountSid, authToken, { accountSid: subaccountSid });
Perform your action through that client using the subaccount Sid that is now attached.
I would like to add some additional info for anyone using twilio subaccounts.
So what I did was create a master account with twilio. This gives you an accountSid and authToken.
These you can store in Heroku under config vars.
When you create your login function for a user via passport login, google-passport or some custom login you create, make your api call to create a subaccount. ( Like when you buy numbers, you buy them under your main account and drill them to your sub accounts) When this is created ONLY add the sub account accountSid to your user object. the sub accountSid is worthless without the auth-token and since you need to make an api call with your env vars your sub account auth tokens are safely stored in twilio.
Now whenever you need to make twilio api calls, say for sending a message or making a phone call etc... first make a call to this endpoint
client.api.v2010.accounts(subActServiceSid)
.fetch()
.then(account => account.authToken);
const accountSid = keys.accountSid // master accountSid
const authToken = keys.authToken // master authToken
// these will be stored in heroku
const listChatMessages = async (req, res) => {
const { subActServiceSid } = req.user // getting sub accountSid from user object
const subActAuthToken = client.api.v2010.accounts(subActServiceSid)
.fetch()
.then(account => account.authToken);
const subClient = require('twilio')(subActServiceSid, subActAuthToken)
await subClient.messages.list({ // make all the api calls your heart desires
from: chat.phone
})
.then( messages => messages.forEach((m) => { console.log("message", m})
this will contain a JSON object with the sub accounts authToken. You can then use this authToken for the API call. No need to worry about storing 100,000 users authTokens somewhere.... If this is still confusing message me.

firebase.auth().currentUser returning null

In the html file that I have for the sign-in page, I perform the authentication using Firebase and on successful authentication, I redirect the given user to the homepage. When I call firebase.auth().currentUser in the express file, I use for rendering and routing pages, I get undefined or null for the current user.
Can anyone help me understand what the issue might be?
This is how I perform the authentication:
firebase
.auth()
.signInWithEmailAndPassword(temail, tpass)
.then(function(firebaseUser) {
window.location.href = "http://localhost:5000/homepage";
})
.catch(function(error) {
window.alert("incorrect pass");
});
This is the code that I have in my express file:
app.get("/homepage", (req, res) => {
var user = firebase.auth().currentUser;
console.log("USER IS " + user);
res.render("menu", { title: "Welcome" });
});
Backend code doesn't have a sense of "current user". When you sign in on the frontend, the current user is only known on that client. It isn't known on the backend. If you want the backend to know which user is signed in, the client will have to send an ID token to the backend for it to verify. The documentation for the Firebase Admin SDK is used for that on the backend. The client must send the ID token to in the request to your route, and the code handling that route must verify the token in order to know the user that made the request. From the documentation:
If your Firebase client app communicates with a custom backend server, you might need to identify the currently signed-in user on that server. To do so securely, after a successful sign-in, send the user's ID token to your server using HTTPS. Then, on the server, verify the integrity and authenticity of the ID token and retrieve the uid from it. You can use the uid transmitted in this way to securely identify the currently signed-in user on your server.
When the user lands on a new page, Firebase automatically restores their previous authentication state. But to do so, it may have to contact the server, which means that it may take a few moments. While Firebase is restoring the state, auth().currentUser will be null.
To ensure you get the correct authentication state, you should use an authentication state listener, as shown in the documentation on getting the current user:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});

Firebase revoked tokens and authentication

I am creating an flutter app that uses firebase authentication. I have added a change email option and have some questions regarding the sessions.
Firstly, when the user changes their email the refresh token is revoked. The firebase documentation examples make use of the realtime database to keep track of the times when tokens are revoked. These are then checked in the database rules. The example to update the database can be seen below
const metadataRef = admin.database().ref('metadata/' + uid);
metadataRef.set({revokeTime: utcRevocationTimeSecs})
.then(() => {
console.log('Database updated successfully.');
});
https://firebase.google.com/docs/auth/admin/manage-sessions#detect_id_token_revocation_in_the_sdk
I'm not sure where to call this code when the email address is changed via the client sdk. Is there a email updated firebase function trigger that I am missing where this timestamp can be written?
I thought about just calling a firebase function but what stops this from being commented out before an attacker updates the email.
Thanks.

Azure App Service Easy Auth

I have an Azure mobile backend set up with easy auth for facebook and google authentication and it works as expected.
Every time a user signs in with any of the supported providers, I want to be able to verify if it's a new user or not (e-mail not in database), without make an additional call from client. Is this possible?
Every time a user signs in with any of the supported providers, I want to be able to verify if it's a new user or not (e-mail not in database), without make an additional call from client. Is this possible?
As far as I know, we couldn't directly verify if it's a new user or not.
No matter you use server flow or client flow, easy auth will just return access token for the client to access the mobile backend resources, it will not check the user is new or old.
If you want to achieve this requirement, you need write your own logic.
You could write codes after the user login successfully.
For example, facebook login.
If you the use have login successfully,you could call GetAppServiceIdentityAsync extension method to get the login credentials, which include the access token needed to make requests against the Facebook Graph API.
// Get the credentials for the logged-in user.
var credentials =
await this.User
.GetAppServiceIdentityAsync<FacebookCredentials>(this.Request);
if (credentials.Provider == "Facebook")
{
// Create a query string with the Facebook access token.
var fbRequestUrl = "https://graph.facebook.com/me/feed?access_token="
+ credentials.AccessToken;
// Create an HttpClient request.
var client = new System.Net.Http.HttpClient();
// Request the current user info from Facebook.
var resp = await client.GetAsync(fbRequestUrl);
resp.EnsureSuccessStatusCode();
// Do something here with the Facebook user information.
var fbInfo = await resp.Content.ReadAsStringAsync();
}
Then you could check the database according to the user information.
More details about how to get user information in server side, you could refer to How to: Retrieve authenticated user information.

Firebase REST auth when creating token with node.js admin sdk

I know this issue was asked a lot here, but I still cannot seem to find the exact answer that can solve my problem.
I wish to access Firebase using REST calls, by adding an access_token param.
The access_token is created using the Node.js Admin SDK, using the following code:
var admin = require("firebase-admin");
var serviceAccount = require("./pk.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://XXX.firebaseio.com"
});
var uid = "1234";
admin.auth().createCustomToken(uid)
.then(function(customToken) {
// Send token back to client
console.log("Token: "+customToken);
})
.catch(function(error) {
console.log("Error creating custom token:", error);
});
The problem is that if I take the token created from Node.js and use it my REST call, I get an Unauthorized request error.
I have read in some questions that people added the scope param when issuing the token, but have not found a way to do that with Node.js Admin SDK.
Google's docs are not so detailed with this issue. Any idea what I might try to resolve this one?
The token you are using to authenticate to the Firebase REST API is not the correct type of token. You are using a Firebase Auth custom token, which can only be used to authenticate one of the Firebase client SDKs via the signInWithCustomToken() method as explained in Sign in using custom tokens on clients.
In order to authenticate to the Firebase REST API, you have two options: Firebase ID tokens (for user-based access) or Google OAuth2 access tokens (for admin access).
Authenticate with Firebase ID Tokens
See Retrieve ID tokens on the client for an explanation of how to retrieve access tokens in the various Firebase client SDKs. You can also exchange a Firebase custom token for an ID token and refresh token pair via an undocumented REST API:
Endpoint: https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key=<API_KEY>
Method: POST
Request Body: { "token": <CUSTOM_TOKEN>, "returnSecureToken": true }
<API_KEY> is the same API key you get from your Firebase Console that you use in the Firebase clients. <CUSTOM_TOKEN> is a Firebase custom token.
Since ID tokens expire after an hour, you will need to use the refresh token to refresh them via this other undocumented REST API:
Endpoint: https://securetoken.googleapis.com/v1/token?key=<API_KEY>
Method: POST
Request Body: { "refresh_token": <REFRESH_TOKEN>, "grant_type": "refresh_token" }
<API_KEY> is the same API key as before. <REFRESH_TOKEN> is the refresh token from the previous API call.
Once you have an ID token, you can pass that to the REST API via the auth query parameter to authenticate a request. The request respects Firebase Security Rules as if the end user logged into the client was making the request.
Authenticate with Google Access Tokens
To authenticate with a Google OAuth2 access token, the first thing you need to do is get one. See Retrieving an access token for an explanation of how to do this. It only currently includes a Java example, but this is possible in many languages, including Node.js. Once you have an ID token, you can pass that to the REST API via the access_token query parameter to authenticate a request. The request will be made with admin access, overriding all Firebase Security Rules and granting full read and write access.

Resources