Why: You have an app which uses signInWithPhoneNumber function from firebase and your app allow users to create subdomains from your app. Now you have multiple domains which are not added to authorized list of domains on your firebase app. So users wont be able to sign in using phone number from the subdomain. Firebase doesn't allow wildcard to be added.
How: We will create an api which will add the newly created subdomain into the whitelist. This api will be called before user shoots the request to signin with firebase.
Notes:
- You need service account credentials for getConfig and updateConfig operations
- updateConfig replaces the list of domains. So we need to fetch the existing list and append to it.
- Create and get private_key and service account email address from firebase console. Add them as env variables.
Steps:
When user clicks sign in with phone number button, call this api, which will add the subdomain to list of authorized list. Then call signInWithPhoneNumber.
API code:
//add new subdomain to white list
var jwt = require("jsonwebtoken");
export default async function handler(req, res) {
// Get the current time in UTC seconds
const currentTimestamp = Math.floor(Date.now() / 1000);
// Set the expiry time to 60 minutes (60 * 60 seconds) from the current time
const expiryTimestamp = currentTimestamp + 60 * 60;
try {
//create JWT for requesting access token from firebase
const jwtForToken = jwt.sign(
{
iss: process.env.FIREBASE_SA_EMAIL,
scope: "https://www.googleapis.com/auth/identitytoolkit",
aud: "https://oauth2.googleapis.com/token",
iat: currentTimestamp,
exp: expiryTimestamp,
},
`${process.env.FIREBASE_PRIVATE_KEY.replace(/\\n/g, '\n')}`,
{ algorithm: "RS256" }
);
//use the JWT created and request access token from firebase
const data = new URLSearchParams();
data.append("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer");
data.append("assertion", jwtForToken);
const tokenResp = await fetch("https://oauth2.googleapis.com/token", {
method: "POST",
headers: {
"content-type": "application/x-www-form-urlencoded",
},
body: data,
});
const token = await tokenResp.json();
//get current config data from firebase
const configResp = await fetch(
`https://identitytoolkit.googleapis.com/admin/v2/projects/${process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID}/config?key=${process.env.NEXT_PUBLIC_FIREBASE_API_KEY}`,
{
method: "GET",
headers: {
Authorization: `Bearer ${token.access_token}`,
},
}
);
const configData = await configResp.json();
let authorizedDomains = configData.authorizedDomains;
const { domain } = JSON.parse(req.body);
if (authorizedDomains.includes(domain)) {
res.status(200).json({ status: true, result: authorizedDomains });
} else {
//add new domain to whitelist
authorizedDomains.push(domain);
//patch the config to firebase with updated list of domains
const updateRequestBody = new URLSearchParams();
updateRequestBody.append("authorizedDomains", [authorizedDomains]);
const configUpdateResp = await fetch(
`https://identitytoolkit.googleapis.com/admin/v2/projects/${process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID}/config?updateMask=authorizedDomains`,
{
method: "PATCH",
headers: {
Authorization: `Bearer ${token.access_token}`,
},
body: JSON.stringify({ authorizedDomains }),
}
);
res
.status(200)
.json({ status: configUpdateResp.status, result: authorizedDomains });
}
} catch (err) {
// console.log("err", err)
res.status(500).json({ status: false, result: err });
}
}
Top comments (0)