We have a client application that uses Firebase authentication services to handle user management, and ASP.NET web services for the business logic and data storage. Before accessing the data on the server, we need to validate that the user is correctly authenticated and has access to their relevant data.
Firebase generates an authentication token that is valid for a few minutes only. The token can be retrieved using Firebase’s getIdToken method. We need to send the token to the web services application and validate it there before accessing the database.
Server side code (C#):
// Add the FirebaseAdmin NuGet package before adding these using directives
using FirebaseAdmin;
using FirebaseAdmin.Auth;
using Google.Apis.Auth.OAuth2;
// Global Firebase App instance
FirebaseApp firebaseApp = FirebaseApp.Create(new AppOptions()
{
// the credentials file can be downloaded from Firebase portal and added to the project
Credential = GoogleCredential.FromFile("cert/credentials.json")
});
// Method for handling a GET request to the profiles table
// The user token Id is optional and received as part of the HTTP reuest
// e.g. https://cloud1.upwindtec.pt:7002/profiles/rBeQAwFltmSSQDmy?idToken=firebase_secret_token
async Task<IResult> GetProfiles([FromRoute] string? Id,
string? idToken,
DbContext db)
{
if (!string.IsNullOrEmpty(idToken))
{
// If a token Id is provided, validate the user before accessing the table
bool authenticated = false;
try
{
FirebaseToken decodedToken = await FirebaseAuth.GetAuth(firebaseApp).VerifyIdTokenAsync(idToken);
string uid = decodedToken.Uid;
// If the user is requesting a specific profile, make sure it matches the user Id from the token
if (uid != null && uid == Id)
{
authenticated = true;
}
}
catch (Exception ex)
{
Trace.WriteLine($"Error validating idToken: {ex.Message}");
}
if (!authenticated)
{
return TypedResults.Unauthorized();
}
}
...
Client side code (Typescript)
const db = getFirestore(await getAuth().currentUser!.getIdToken()); // add the firebase token Id to the HTTP request
const profileSnapshot = await getDoc(doc(db, "profiles", userID));
...
// adding the token to the request is done this way:
let response: AxiosResponse = {} as AxiosResponse;
// if we have an idToken, add it to the query parameters for authentication purposes
if (this.idToken !== "") {
if (!params) {
params = new URLSearchParams();
}
params.append("idToken", this.idToken);
}
try {
response = await axios({
url: Url,
method: method,
params: params,
data: data,
baseURL: this.baseUrl,
...