Error 403 on Calling Firebase Firestore Rest API - firebase

Here the code how i am generating the accessToken for Calling API.
import firebaseConfig from './../firebaseConfig';
import firebase from "firebase/app";
import "firebase/auth";
firebase.initializeApp(firebaseConfig);
var provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider).then(function(result) {
var token = result.credential.accessToken;
sessionStorage.setItem("__token", token); // Token saved
}.bind(this)).catch(function(error) {
});
With that code i am getting the token in sessionStorage.
Here's the snippet how i am using firebase Rest API.
var URL = https://firestore.googleapis.com/v1/projects/qtbt-a8bf8/databases/(default)/documents/users/[USER_ID]?key=[YOUR_API_KEY]
var token = sessionStorage.getItem("__token");
const config = {
headers: { Authorization: `Bearer ${token}` , Accept: 'application/json'}
};
axios.get(URL, config)
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
.finally(function () {
// always executed
});
In the axios call, i am getting Error 403.
Response:
code: 403
message: "Request had insufficient authentication scopes."
status: "PERMISSION_DENIED"

your missing the api-key in the call. apikey and token should both be in the headers.
var token = sessionStorage.getItem("__token");// verify your token is correct.
var headers = {'x-api-key' : 'key valu goes here', 'authorization': ${token} }

The security rule is slightly different when using an IdToken rather than an OAuth token.
Instead of using:
if request.auth.uid == resource.id;
I use:
if request.auth.token.email == resource.id;
I'm matching the token's owner email to the document id, which also happens to be the owner's email.
You can also access the user's child documents using something like:
request.auth.token.email == resource.data.ownerEa;
In that case, the document(s) being matched must have an attribute ownerEa that has value == user's email.
Very annoying documentation isn't it.
Hope that helps...

Related

Firebase google authentication in Chrome Extension - Error getting credential

I'm working on updating a chrome extension to MV3, and therefore I can't use the firebase UI to login any more. What I trying to do is use chrome.identity.launchWebAuthFlow, get the token, create the credential, and sign in with firebase.
Here's what I have:
function launchGoogleAuthFlow(interactive) {
return new Promise((resolve, reject) => {
console.log('launching webauthflow')
const manifest = chrome.runtime.getManifest();
const clientId = encodeURIComponent(manifest.oauth2.client_id);
const scopes = encodeURIComponent(manifest.oauth2.scopes.join(' '));
let redirectUri = chrome.identity.getRedirectURL();
let nonce = Math.random().toString(36).substring(2, 15)
const authUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth');
authUrl.searchParams.set('client_id', clientId);
authUrl.searchParams.set('response_type', 'id_token');
authUrl.searchParams.set('redirect_uri', redirectUri);
// Add the OpenID scope. Scopes allow you to access the user’s information.
authUrl.searchParams.set('scope', 'openid profile email');
authUrl.searchParams.set('nonce', nonce);
// Show the consent screen after login.
authUrl.searchParams.set('prompt', 'consent');
chrome.identity.launchWebAuthFlow(
{
'url': authUrl.href,
'interactive': interactive
},
(redirectedTo) => {
if (chrome.runtime.lastError) {
console.log(chrome.runtime.lastError.message);
resolve(null)
}
else {
let idToken = redirectedTo.substring(redirectedTo.indexOf('id_token=') + 9)
idToken = idToken.substring(0, idToken.indexOf('&'))
resolve(idToken)
}
}
)
})
}
launchGoogleAuthFlow(true).then((token)=>{
if (token) {
console.log('token:' + token);
const credential = GoogleAuthProvider.credential(null, token);
console.log(credential);
signInWithCredential(auth, credential).then((result) => {
showMain();
document.getElementById('loggedInAs').textContent = result.email;
console.log("Success!!!")
console.log(result)
}).catch((error) => {
// You can handle errors here
console.log(error)
});
} else {
console.error('The OAuth token was null');
}
});
console.log('finished authflow');
}
I'm getting prompted to sign in with my google credentials, then in the console I get Failed to load resource: the server responded with a status of 400 ()
and then the a log from SignInWithCredentials
FirebaseError: Firebase: Unsuccessful check authorization response from Google: {
"error_description": "Invalid Value"
}
(auth/invalid-credential).
at _errorWithCustomMessage (index-6bd8d405.js:453:1)
at _performFetchWithErrorHandling (index-6bd8d405.js:973:1)
at async _performSignInRequest (index-6bd8d405.js:988:1)
at async _signInWithCredential (index-6bd8d405.js:4721:1)
In the response_type you are requesting an id_token:
authUrl.searchParams.set('response_type', 'id_token');
So your launchGoogleAuthFlow returns an id_token and that's it what you must give to GoogleAuthProvider.credential. This method expects an a id_token as the first parameter and an a access_token as the second parameter.
So all you have to do is change from:
const credential = GoogleAuthProvider.credential(null, token);
to:
const credential = GoogleAuthProvider.credential(token);
Everything should works fine.
If you may want the access_token you must request response_type=token and remove nonce. Finally you'll need to extract the returned access_token from response URL (your redirectedTo variable) as you did with id_token.
PS: In your code I also noticed that you got scopes from manifest but did not use them while requesting the token.

Google OAuth Refresh Tokens not returning Valid Access Tokens

I have a Firebase application that authenticates a user and returns an access token that I can then use to access the Google Calendar and Sheets API. I also save the refreshToken. Sample code for authenticated token:
firebase
.signInWithGoogle()
.then(async (socialAuthUser) => {
let accessToken = socialAuthUser.credential.accessToken // token to access Google Sheets API
let refreshToken = socialAuthUser.user.refreshToken
this.setState({accessToken, refreshToken})
})
After 1 hour, the accessToken expires. Firebase auth provides a refresh token on the user object after sign-in
I use that refresh token to re-authenticate and get a new access_token by posting to:
https://securetoken.googleapis.com/v1/token?key=firebaseAppAPIKey
That new access token does not work for Google APIs anymore, and it doesn't have the authorized scopes anymore. I also try sending it to
https://www.googleapis.com/oauth2/v1/tokeninfo?access_token="refreshToken"
It gives me the error "Invalid token". When I use the original token from firebase, it works just fine.
Anyone else encountering a similar issue? I haven't figured out a way to refresh the original access token with the correct access scopes without making the user sign-out and sign-in again.
Thanks!
I was finally able to solve it after many attempts.
Posted detailed solution on Medium: https://inaguirre.medium.com/reusing-access-tokens-in-firebase-with-react-and-node-3fde1d48cbd3
On the client, I used React with the Firebase library, and on the server I used Node.js with the packages google-apis and the firebase-admin skd package linked to the same Firebase project.
Steps:
(CLIENT) Send a request to the server to generate an authentication link
(SERVER) Generate Auth Link and send it back to the client using the getAuthLink() from googleapis. Sign in with Google and handle the redirect.
(SERVER) On the redirect route, use the code from Google on the query string to authenticate the user and get his user credentials. Use these credentials to check if the user is registered on Firebase.
(SERVER) If the user is registered, get the access and refresh tokens using the oauth2.getTokens(code), update refresh token on the user profile in the database. If the user is not registered, create a new user with firebase.createUser(), also create the user profile on the database with the refresh token.
(SERVER) Use firebase.createCustomToken(userId) to send an id_token back to client and authenticate.
(SERVER) Use a res.redirect({access_token, referesh_token, id_token}) to send credentials back to client.
(CLIENT) On the client, use the signInWithCustomToken(id_token) to authenticate, also restructure the query to obtain access_token and refresh_token to send API calls.
(CLIENT) Set an expiration date for the access token. On each request, check if the current date is higher than the expiration date. If it is, request a new token to https://www.googleapis.com/oauth2/v4/token with the refresh token. Otherwise use the access_token stored.
Most stuff happens when handling the Google Redirect after authentication. Here's an example of handling auth and tokens on the backend:
const router = require("express").Router();
const { google } = require("googleapis");
const { initializeApp, cert } = require("firebase-admin/app");
const { getAuth } = require("firebase-admin/auth");
const { getDatabase } = require("firebase-admin/database");
const serviceAccount = require("../google-credentials.json");
const fetch = require("node-fetch");
initializeApp({
credential: cert(serviceAccount),
databaseURL: "YOUR_DB_URL",
});
const db = getDatabase();
const oauth2Client = new google.auth.OAuth2(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET,
"http://localhost:8080/handleGoogleRedirect"
);
//post to google auth api to generate auth link
router.post("/authLink", (req, res) => {
try {
// generate a url that asks permissions for Blogger and Google Calendar scopes
const scopes = [
"profile",
"email",
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/calendar",
];
const url = oauth2Client.generateAuthUrl({
access_type: "offline",
scope: scopes,
// force access
prompt: "consent",
});
res.json({ authLink: url });
} catch (error) {
res.json({ error: error.message });
}
});
router.get("/handleGoogleRedirect", async (req, res) => {
console.log("google.js 39 | handling redirect", req.query.code);
// handle user login
try {
const { tokens } = await oauth2Client.getToken(req.query.code);
oauth2Client.setCredentials(tokens);
// get google user profile info
const oauth2 = google.oauth2({
version: "v2",
auth: oauth2Client,
});
const googleUserInfo = await oauth2.userinfo.get();
console.log("google.js 72 | credentials", tokens);
const userRecord = await checkForUserRecord(googleUserInfo.data.email);
if (userRecord === "auth/user-not-found") {
const userRecord = await createNewUser(
googleUserInfo.data,
tokens.refresh_token
);
const customToken = await getAuth().createCustomToken(userRecord.uid);
res.redirect(
`http://localhost:3000/home?id_token=${customToken}&accessToken=${tokens.access_token}&userId=${userRecord.uid}`
);
} else {
const customToken = await getAuth().createCustomToken(userRecord.uid);
await addRefreshTokenToUserInDatabase(userRecord, tokens);
res.redirect(
`http://localhost:3000/home?id_token=${customToken}&accessToken=${tokens.access_token}&userId=${userRecord.uid}`
);
}
} catch (error) {
res.json({ error: error.message });
}
});
const checkForUserRecord = async (email) => {
try {
const userRecord = await getAuth().getUserByEmail(email);
console.log("google.js 35 | userRecord", userRecord.displayName);
return userRecord;
} catch (error) {
return error.code;
}
};
const createNewUser = async (googleUserInfo, refreshToken) => {
console.log(
"google.js 65 | creating new user",
googleUserInfo.email,
refreshToken
);
try {
const userRecord = await getAuth().createUser({
email: googleUserInfo.email,
displayName: googleUserInfo.name,
providerToLink: "google.com",
});
console.log("google.js 72 | user record created", userRecord.uid);
await db.ref(`users/${userRecord.uid}`).set({
email: googleUserInfo.email,
displayName: googleUserInfo.name,
provider: "google",
refresh_token: refreshToken,
});
return userRecord;
} catch (error) {
return error.code;
}
};
const addRefreshTokenToUserInDatabase = async (userRecord, tokens) => {
console.log(
"google.js 144 | adding refresh token to user in database",
userRecord.uid,
tokens
);
try {
const addRefreshTokenToUser = await db
.ref(`users/${userRecord.uid}`)
.update({
refresh_token: tokens.refresh_token,
});
console.log("google.js 55 | addRefreshTokenToUser", tokens);
return addRefreshTokenToUser;
} catch (error) {
console.log("google.js 158 | error", error);
return error.code;
}
};
router.post("/getNewAccessToken", async (req, res) => {
console.log("google.js 153 | refreshtoken", req.body.refresh_token);
// get new access token
try {
const request = await fetch("https://www.googleapis.com/oauth2/v4/token", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
client_id: process.env.GOOGLE_CLIENT_ID,
client_secret: process.env.GOOGLE_CLIENT_SECRET,
refresh_token: req.body.refresh_token,
grant_type: "refresh_token",
}),
});
const data = await request.json();
console.log("google.js 160 | data", data);
res.json({
token: data.access_token,
});
} catch (error) {
console.log("google.js 155 | error", error);
res.json({ error: error.message });
}
});
module.exports = router;
For anyone who comes across this now, there is a much easier way at this point.
I was able to solve this by implementing a blocking function that simply saved the refreshToken and exiry date to firestore. You can then query this from your frontend to get the tokens there as well.
Be sure to enable the refreshToken in the firebase settings, otherwise the blocking function won't have access to it.
https://firebase.google.com/docs/auth/extend-with-blocking-functions
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import {
AuthEventContext,
AuthUserRecord,
} from "firebase-functions/lib/common/providers/identity";
admin.initializeApp();
exports.beforeSignIn = functions.auth
.user()
.beforeSignIn((user: AuthUserRecord, context: AuthEventContext) => {
// If the user is created by Yahoo, save the access token and refresh token
if (context.credential?.providerId === "yahoo.com") {
const db = admin.firestore();
const uid = user.uid;
const data = {
accessToken: context.credential.accessToken,
refreshToken: context.credential.refreshToken,
tokenExpirationTime: context.credential.expirationTime,
};
// set will add or overwrite the data
db.collection("users").doc(uid).set(data);
}
});

Where do you get/find the JWT-Secret from firebase?

I'm using firebase for my web/mobile apps and now have a back-end API I'm looking to use as well.
The API requires a JWT token to authenticate the requests and to set it up, I need to specify the JWT Secret that is used to encrypt/decrypt the token.
In firebase, I believe I retrieve the token using
const token = await firebase.auth().currentUser.getIdToken(); This is what I pass to the API.
However, I have not figured out where I get the JWT-secret to configure? I have tried the API key that is shown in firebase console, I have also tried the server/client keys found at my console at https://console.developers.google.com.
however, no matter what, I'm getting a JWSInvalidSignature when trying to make requests to the API Call.
Has anyone got this working? Where do I get the JWT-secret from firebase to configure on the API back-end? Thanks in advance.
Here are the details:
1. I am using a service called postGrest which auto-creates a web API on top of postgres DB. In order to authenticate the requests, you configure the service by specifying a custom claim called "role", and you also need to specify the JWT-secret so it can decode the token.
Here is my simple call to the API:
const fetchdata = async () => {
const token = await firebase.auth().currentUser.getIdToken();
let axiosConfig = {
headers: {
'Authorization': 'Bearer' + token
}
}
const data = await axios.get(`http://localhost:8080/users`,
axiosConfig);
}
Also note, I can simulate this in the bash command line using the following code: Note here that I'm getting the token from the getIdToken() above.
export TOKEN="eyJhbGciOiJSUzI1NiIsImtpZCI6ImQ2YzM5Mzc4YWVmYzA2YzQyYTJlODI1OTA0ZWNlZDMwODg2YTk5MjIiLCJ0eXAiOiJKV1QifQ.eyJ1c2VyaWQiOiI1NSIsImlzcyI6Imh0dHBzOi8vc2VjdXJldG9rZW4uZ29vZ2xlLmNvbS9wb3N0Z3Jlc3QtYjRjOGMiLCJhdWQiOiJwb3N0Z3Jlc3QtYjRjOGMiLCJhdXRoX3RpbWUiOjE1NzExNTIyMjQsInVzZXJfaWQiOiJNMXZwQ3A2ZjlsaFdCblRleHh1TjlEdXIzUXAyIiwic3ViIjoiTTF2cENwNmY5bGhXQm5UZXh4dU45RHVyM1FwMiIsImlhdCI6MTU3MTE1OTQ0NSwiZXhwIjoxNTcxMTYzMDQ1LCJlbWFpbCI6InNwb25nZWJvYkBnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsic3BvbmdlYm9iQGdtYWlsLmNvbSJdfSwic2lnbl9pbl9wcm92aWRlciI6InBhc3N3b3JkIn19.nKuovs0Gx_ZKp17dI3kfz6GQofIMEOTA8RqTluwEs-5r-oTbKgpG33uS7fs7txVxvWIb_3fbN3idzfDHZevprMkagbHOd73CxTFBM7pr1bD2OKSK9ZPYfSt9OhvgJL51vBN3voLcNAb5iWVVl2XMqkcXeDoBi8IOKeZr27_DsRx48GSi7HieHWscF1lujSEr2C9tdAek3YyNnr3IcGI8cTSPHPaIbYl-8CaHQO2fUiGHEAaD7sqHxp3otJio56zOoNAy44P_nwORlMFZC0Rm8SaATpbmIkgbGYWHZHty70lmlYGVHTuM_hr2s7z2YhAjuacvBMgusZpyoVnoe3FQeA"
curl http://localhost:8080/contacts -H "Authorization: Bearer $TOKEN"
What's returned is: {"message":"JWSError JWSInvalidSignature"}
For the JWT-secret, I have tried several values, but none seem to work. This includes the "API Key" from firebase project, as well as trying "Generate key" which downloads a new .json file and inside there is a "private_key": that is along string.
From your service account downloaded file, use the private_key value to validate/decode the JWT token you got from getIdToken()...
The steps for using a third-party library to validate a Firebase Auth ID token describe it in more detail.
First you need to get your service_account.json
Then setup firebase on your server.
Example:
// set_up_firebase.js
const admin = require("firebase-admin");
var serviceAccount = require("./service_account.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
storageBucket: "your-app.appspot.com"
});
exports.admin = admin;
Then create a middleware function to check jwt.
Example:
// verifyJWT.js
const fire = require("./set_up_fire.js");
function _getToken(req) {
return req.headers.authorization !== undefined
&& req.headers.authorization !== ""
&& req.headers.authorization.split(' ').length === 2
&& req.headers.authorization.split(' ')[1] !== undefined
&& req.headers.authorization.split(' ')[1] !== ""
? req.headers.authorization.split(' ')[1]
: "";
}
function getJWTExpiredPayload() {
return { "status": 401, "result": "ERROR", "error": "Unauthorized!" };
}
function getJWTNotValidPayload() {
return { "status": 403, "result": "ERROR", "error": "Forbidden!" };
}
module.exports = async (req, res, next) => {
const token = _getToken(req);
let verified = undefined;
if (token !== undefined && token !== null && token !== "") {
try {
verified = await fire.admin.auth().verifyIdToken(token, true);
if (verified !== undefined && verified["exp"] !== undefined
&& Date.now() < verified["exp"] * 1000) {
req.user = verified;
return next();
}
return res.status(401).json(getJWTExpiredPayload());
} catch (error) {
console.log(error);
}
}
return res.status(403).json(getJWTNotValidPayload());
}
Then in your router, call it before your api:
Example with Express:
const verifyJWT = require("./jwt/verifyJWT.js");
router.post("/verifyJWT", verifyJWT, (req, res) => {
return res.status(200);
})

OAuth2 fails to return auth token using simple-oauth2 and Firebase Functions for Spotify Authentication

I have been working on a oauth2 flow for spotify by following this similar tutorial by the Firebase team for Instagram HERE
I am able to submit my credentials and return the user code and state in the url, but when I run the method to submit the code to return an auth token, the auth token that I print to console in the Firebase functions returns: Auth Token Error Not Found. Here's my workflow:
Here's the Spotify docs
FIRST, I have a function to configure my spotifyOAuth:
function spotifyOAuth2Client() {
// Spotify OAuth 2 setup
const credentials = {
client: {
id: functions.config().spotify.clientid,
secret: functions.config().spotify.clientsecret,
},
auth: {
tokenHost: 'https://accounts.spotify.com',
authorizePath: '/authorize'
},
};
return require('simple-oauth2').create(credentials);
}
I use that function in this Firebase function that is called using https://us-central1-<my project string>.cloudfunctions.net/redirect:
exports.redirect = functions.https.onRequest((req, res) => {
const oauth2 = spotifyOAuth2Client();
cookieParser()(req, res, () => {
const state = req.cookies.state || crypto.randomBytes(20).toString('hex');
console.log('Setting verification state:', state);
res.cookie('state', state.toString(), {
maxAge: 3600000,
secure: true,
httpOnly: true,
});
const redirectUri = oauth2.authorizationCode.authorizeURL({
redirect_uri: OAUTH_REDIRECT_URI,
//scope: OAUTH_SCOPES,
state: state,
});
console.log('Redirecting to:', redirectUri);
res.redirect(redirectUri);
});
});
The code above returns a url string with the proper parameters, the following code block is where my code breaks, I have another cloud function that runs after being redirected from the res.redirect(redirectUri) above. And when I try to run the getToken() method, it appears to not return anything because I hit the catch block instead? This is where I observe the Auth Token Error Not Found.
const oauth2 = spotifyOAuth2Client();
try {
return cookieParser()(req, res, async () => {
console.log('Received verification state:', req.cookies.state);
console.log('Received state:', req.query.state);
if (!req.cookies.state) {
throw new Error('State cookie not set or expired. Maybe you took too long to authorize. Please try again.');
} else if (req.cookies.state !== req.query.state) {
throw new Error('State validation failed');
}
console.log('Received auth code:', req.query.code);
console.log(OAUTH_REDIRECT_URI);
// Get the access token object (the authorization code is given from the previous step).
const tokenConfig = {
code: req.query.code,
redirect_uri: 'http://localhost:8100/popup'
};
// Save the access token
try {
const result = await oauth2.authorizationCode.getToken(tokenConfig)
const accessToken = oauth2.accessToken.create(result);
console.log('inside try');
console.log(result);
console.log(accessToken);
} catch (error) {
console.log('Access Token Error', error.message);
}
I've double checked my spotify client/secret credentials in the config, what is going wrong with this OAuth2 flow?
Resolved my issue, I was not using the correct endpoints:
const credentials = {
client: {
id: functions.config().spotify.clientid,
secret: functions.config().spotify.clientsecret,
},
auth: {
tokenHost: 'https://accounts.spotify.com',
authorizePath: '/authorize',
tokenPath: '/api/token'
},
};

How to use the Firebase refreshToken to reauthenticate?

I use the JS library call firebase.auth().signInWithEmailAndPassword(email, password) and get back a User object. The User object contains a refreshToken.
I use curl 'https://docs-examples.firebaseio.com/rest/saving-data/auth-example.json?auth=TOKEN' to make calls to Firebase.
The token will eventually expire. In order to make it look like the application (iOS and macOS) has persistent login, I want to refresh the token, how do I do that with using either the REST or JS library? I can't find any calls in the documentation that allow me to use the refreshToken to get a new token.
When you make call from a browser .getIdToken(true) will automatically refresh your token. Make call like this:
firebase.auth().currentUser.getIdToken(/ forceRefresh / true)
.then(function(idToken) {
}).catch(function(error) {
});
More info here https://firebase.google.com/docs/reference/js/firebase.User#getIdToken
** UPDATE ** this is also now documented in Firebase REST docs under Exchange a refresh token for an ID token section:
https://firebase.google.com/docs/reference/rest/auth/#section-refresh-token
Currently the only way I found to do this is here:
https://developers.google.com/identity/toolkit/reference/securetoken/rest/v1/token
You must make an HTTP request:
POST https://securetoken.googleapis.com/v1/token?key=YOUR_KEY
Where YOUR_KEY can be found in the Google developers console > API Manager > Credentials. It's under the API Keys section.
Make sure request body is structured in the following format:
grant_type=refresh_token&refresh_token=REFRESH_TOKEN
Where REFRESH_TOKEN is the refresh token from Firebase user object when they signed in.
You must set the header Content-Type: application/json or you will get errors (e.g. "MISSING_GRANT_TYPE").
The POST call will return a new idToken (used to be called access_token)
I guess most people here are looking for a way to persist their authentication not in a browser but e.g. on a node backend. Turns out there actually is a way to do this:
Trade the refresh-token for an access-token (using google's public api)
Trade the access-token for a custom-token (using a firebase-function, see below)
Login with custom-token
Here's the essence of the code:
const requestP = require('request-promise');
const fsP = require('fs').promises;
const refreshToken = await fsP.readFile('./refresh_token.txt');
const res = await requestP.post({
headers: {'content-type': 'application/x-www-form-urlencoded'},
url: 'https://securetoken.googleapis.com/v1/token?key=' + firebaseConf.apiKey,
body: 'grant_type=refresh_token&refresh_token=' + refreshToken,
json: true
});
const customToken = await requestP.post({
headers: {'content-type': 'text/plain'},
url: 'https://<yourFirebaseApp>.cloudfunctions.net/createCustomToken',
body: {token: res.access_token},
json: true
});
await firebaseApp.auth().signInWithCustomToken(customToken);
And the firebase function:
export const createCustomToken = functions.https.onRequest(async (request, response) => {
response.set('Access-Control-Allow-Origin', '*');
try {
const token = JSON.parse(request.body).token;
const decodedToken = await admin.auth().verifyIdToken(token);
const customToken = await admin.auth().createCustomToken(decodedToken.uid);
response.send(customToken);
} catch(e) {
console.log(e);
response.sendStatus(500);
}
});
// Create a callback which logs the current auth state
function authDataCallback(authData) {
if (authData) {
console.log("User " + authData['uid'] + " is logged with token" + authData['ie']);
} else {
console.log("User is logged out");
}
}
// Register the callback to be fired every time auth state changes
var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.onAuth(authDataCallback);
Event onAuth will be called on page refresh, if user was logged out authData will be null, else not. You can find token in authdata['ie']. In the screenshot bellow I have printed the token after auth and authdata object, how you can see authData['ie'] and token are similar.

Resources