Verify the Firebase authentication token of a user's request on an Google App Engine NodeJS server? - node.js

So I've found this piece of doc on how to integrate Firebase authentication with Google App Engine, but it was written for Python, and it seems old, as I've found some inconsistencies in the code. I didn't find a corresponding tutorial for NodeJS.
From I understood, the sequence of the process should be the following:
STEP 1
User logs in through client code (firebase JS SDK) and I get its JWT userIdToken by using user.getIdToken()
STEP 2
Fetch my GAE server URL with the following header:
headers: {
'Authorization': 'Bearer ' + userIdToken
}
Then the tutorial indicates that I should use a Google Auth library, in order to validate the JWT userIdToken.
Before the client can access server data, your server must verify the token is signed by Firebase. You can verify this token using the Google Authentication Library for Python. Use the authentication library's verify_firebase_token function to verify the bearer token and extract the claims:
Therefore, for a NodeJS server, I should use the following library, correct?
google-auth-library
Or instead, can I use firebase-admin to validate the userIdToken as indicated in the following doc?
https://firebase.google.com/docs/auth/admin/verify-id-tokens
I guess that the firebase-admin seems to be the way to go on this case. But if I choose that path, should I still pass the token using the 'Authorization': 'Bearer ' header? Or is there a better way of handling this?

You can pass the ID token to your backend any way you want. It's customary and standard to use the Authorization header as you see in the documentation, but not required. The code examples should make it clear that what you really just need is to pass that token to be verified with the Firebase Admin SDK.

Related

What is the best way to call an authenticated HTTP Cloud Function from Node JS app deployed in GCP?

We have an authenticated HTTP cloud function (CF). The endpoint for this CF is public but because it is authenticated, it requires a valid identity token (id_token) to be added to the Authorization header.
We have another Node JS application that is deployed in the same Google Cloud. What we want is to call the CF from the Node application, for which we will be needing a valid id token.
The GCP documentation for authentication is too generic and does not have anything for such kind of scenario.
So what is the best way to achieve this?
Note
Like every google Kubernetes deployment, the node application has a service account attached to it which already has cloud function invoker access.
Follow Up
Before posting the question here I had already followed the same approach as #guillaume mentioned in his answer.
In my current code, I am hitting the metadata server from the Node JS application to get an id_token, and then I am sending the id_token in a header Authorization: 'Bearer [id_token]' to the CF HTTP request.
However, I am getting a 403 forbidden when I do that. I am not sure why??
I can verify the id_token fetched from the metadata server with the following endpoint.
https://www.googleapis.com/oauth2/v1/tokeninfo?id_token=[id_token]
It's a valid one.
And it has the following fields.
Decoding the id_token in https://jwt.io/ shows the same field in the payload.
{
"issued_to": "XXX",
"audience": "[CLOUD_FUNTION_URL]",
"user_id": "XXX",
"expires_in": 3570,
"issuer": "https://accounts.google.com",
"issued_at": 1610010647
}
There is no service account email field!
You have what you need in the documentation but I agree, it's not clear. It's named function-to-function authentication.
In fact, because the metadata server is deployed on each computes element on Google Cloud, you can reuse this solution everywhere (or almost everywhere! You can't generate an id_token on Cloud Build, I wrote an article and a workaround on this)
This article provides also a great workaround for local testing (because you don't have metadata server on your computer!)

authentication header vs query parameter in google cloud endpoints

I have tried everything, yet I cannot access my API using google cloud endpoints using a Authentication:Bearer header. According to Cloud Endpoints Docs:
When you send a request using an authentication token, for security reasons, we recommend that you put the token in the Authorization:Bearer header.
it also says:
If you cannot use the header when sending the request, you can put the authentication token in a query parameter called access_token.
I can perfectly access the API using access_token=" +idToken in my URL. However, when I try to send an HTTP request with the Authentication header like this:
const url =
"https://<PROJECTNAME>.appspot.com/getbalance";
axios
.get(url,{headers:{'Authentication':'Bearer '+idToken}})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.log(error);
});
I get this error:
JWT validation failed: Missing or invalid credentials
Is sending the token in a query parameter as safe as sending it in the header?
Your code example shows you setting an Authentication header, not an Authorization header. You should not typically use a query parameter as it will likely get logged in Cloud Console.
When using "Authorization: Bearer ", you would need to use an access token obtained through OAuth 2.0 authentication.
This can be illustrated if you use the Oauth Playground agains any of the Google APIs.
Keep in mind that if you want to access your Firebase database using the Oauth Playground, you would need to configure the client ID and client Secret of your Firebase project on the gear icon at the top right of the playground screen.
Also make sure to use these scopes:
https://www.googleapis.com/auth/userinfo.email
https://www.googleapis.com/auth/firebase.database
After completing all the steps, you will be able to make a REST request using the authorization header with the obtained access token.

Using JSON Web Tokens (JWT) with Azure Functions (WITHOUT using Active Directory)

I am sure someone out there has already done this, but I have yet to find any documentation with regard to the Microsoft implementation of JWT. The official documentation from Microsoft for their JWT library is basically an empty page, see:
https://learn.microsoft.com/en-us/dotnet/framework/security/json-web-token-handler-api-reference
So, here is what I (and I am sure many others) would like to accomplish:
Definition: User ID = The username or email address used to log into a system.
AUTHENTICATION:
A user logs in. The user fills in web form and the system sends (via HTTPS POST) the users ID and password (hashed) to the server in order to authenticate / validate the user.
Server Authenticates user. The users ID and password are checked against the values saved in the database and if NOT valid, an invalid login response is returned to the caller.
Create a JWT Token - ???? No documentation available!
Return the JWT token to the caller - ???? - I assume in a header? via JSON, not sure -- again - no documentation.
Given the code below, can anyone provide a code example for steps 3 and 4?
[FunctionName( "authenticate" )]
public static async Task<HttpResponseMessage> Run( [HttpTrigger( AuthorizationLevel.Anonymous, "get", "post", Route = null )]HttpRequestMessage req, TraceWriter log )
{
// Step 1 - Get user ID and password from POST data
/*
* Step 2 - Verify user ID and password (compare against DB values)
* If user ID or password is not valid, return Invalid User response
*/
// Step 3 - Create JWT token - ????
// Step 4 - Return JWT token - ????
}
AUTHORIZATION:
Assuming the user was authenticated and now has a JWT token (I am assuming the JWT token is saved in the users session; if someone wants to provide more info, please do):
A POST request is made to an Azure Function to do something (like get a users birth date). The JWT token obtained above is loaded (from the POST data or a header - does it matter?) along with any other data required by the function.
The JWT token is validated - ???? No documentation available!
If the JWT token is NOT valid, a BadRequest response is returned by the function.
If the JWT token is valid, the function uses the data passed to it to process and issue a response.
Given the code below, can anyone provide a code example for steps 1 and 2?
[FunctionName( "do_something" )]
public static async Task<HttpResponseMessage> Run( [HttpTrigger( AuthorizationLevel.Anonymous, "get", "post", Route = null )]HttpRequestMessage req, TraceWriter log )
{
// Step 1 - Get JWT token (from POST data or headers?)
// Step 2 - Validate the JWT token - ???
// Step 3 - If JWT token is not valid, return BadRequest response
// Step 4 - Process the request and return data as JSON
}
Any and all information would really help those of us (me) understand how to use JWT with Azure (anonymous) functions in order to build a "secure" REST API.
Thanks in advance.
Any and all information would really help those of us (me) understand how to use JWT with Azure (anonymous) functions in order to build a "secure" REST API.
Per my understanding, you could use the related library in your azure function code to generate / validate the JWT token. Here are some tutorials, you could refer to them:
Create and Consume JWT Tokens in C#.
Jwt.Net, a JWT (JSON Web Token) implementation for .NET
JWT Authentication for Asp.Net Web Api
Moreover, you could leverage App Service Authentication / Authorization to configure the function app level Authentication / Authorization. You could go to your Function App Settings, click "NETWORKING > Authentication / Authorization" under the Platform features tab. Enable App Service Authentication and choose Allow Anonymous requests (no action) as follows:
You could create a HttpTrigger function with anonymous accessing for user logging and return the JWT token if the user exists. For the protected REST APIs, you could follow the code sample below:
if(System.Security.Claims.ClaimsPrincipal.Current.Identity.IsAuthenticated)
{
//TODO: retrieve the username claim
return req.CreateResponse(HttpStatusCode.OK,(System.Security.Claims.ClaimsPrincipal.Current.Identity as ClaimsIdentity).Claims.Select(c => new { key = c.Type, value = c.Value }),"application/json");
}
else
{
return req.CreateResponse(HttpStatusCode.Unauthorized,"Access Denied!");
}
For generating the JWT token used in App Service Authentication, you could follow How to: Use custom authentication for your application and the code under custom API controller CustomAuthController from adrian hall's book about Custom Authentication to create the JWT token.
UPDATE:
For the custom authentication approach under App Service Authentication, I just want op to leverage the authentication / Authorization provided by EasyAuth. I have did some test for this approach and found it could work on my side. Op could send the username and password to the HttpTrigger for authentication, then the HttpTrigger backend need to validate the user info, and use Microsoft.Azure.Mobile.Server.Login package for issuing App Service Authentication token to the client, then the client could retrieve the token from the AuthenticationToken property. The subsequent requests against the protected APIs could look like as follows:
https://<your-funapp-name>.azurewebsites.net/api/<httpTrigger-functionName>
Header: x-zumo-auth:<AuthenticationToken>
NOTE:
For this approach, the related HttpTrigger functions need to allow anonymous accessing and the App Service Authentication also needs to choose Allow Anonymous requests (no action). Otherwise, the App Service Authentication and function level authentication would both validate the request. For the protected APIs, op needs to manually add the System.Security.Claims.ClaimsPrincipal.Current.Identity.IsAuthenticated checking.
Try this: https://liftcodeplay.com/2017/11/25/validating-auth0-jwt-tokens-in-azure-functions-aka-how-to-use-auth0-with-azure-functions/
I successfully made it work using this guide. It took awhile due to nuget versions.
Follow that guide properly and use the following nuget versions
IdentityModel.Protocols (2.1.4)
IdentityModel.Protocols.OpenIdConenct (2.1.4)
IdentityModel.Tokens.Jwt (5.1.4)
Oh and, the guide tells you to write your AUDIENCE as your api link, don't. You'll get unauthorized error. Just write the name of your api, e.g. myapi
If you get error about System.http.formatting not being loaded when running the function, try to reinstall NET.Sdk.Functions and ignore the warning about AspNet.WebApi.Client being restored using .NETFramework. And restart visual studio.
What you're describing is something that you should be able to do yourself by doing a little bit of research. To address your specific questions:
Create a JWT Token - ???? No documentation available!
The link Bruce gave you gives a nice example for how to create a JWT: https://www.codeproject.com/Tips/1208535/Create-And-Consume-JWT-Tokens-in-csharp
Return the JWT token to the caller - ???? - I assume in a header? via JSON, not sure -- again - no documentation.
There's no documentation because you're basically inventing your own protocol. That means how you do it is entirely up to you and your application requirements. If it's a login action, it might make sense to return it as part of the HTTP response payload. Just make sure that you're using HTTPS so that the token stays protected over the wire.
A POST request is made to an Azure Function to do something (like get a users birth date). The JWT token obtained above is loaded (from the POST data or a header - does it matter?) along with any other data required by the function.
How you send the token is, again, entirely up to you. Most platforms use the HTTP Authorization request header, but you don't have to if you don't want to.
The JWT token is validated - ???? No documentation available!
Use the ValidateToken method of the JwtSecurityTokenHandler (see the previous link for how to get the JwtSecurityTokenHandler). Docs here: https://msdn.microsoft.com/en-us/library/dn451155(v=vs.114).aspx.
I created an Azure Functions input binding for JWT Token Validation. You can use this as an extra parameter with the [JwtBinding] attribute. See https://hexmaster.nl/posts/az-func-jwt-validator-binding/ for source and NuGet package information.
Basically Azure Functions built on top of ASP.NET Core. By making some dependency injection tricks you could add your own authentication and policy-based authorization. I created demo solution with JWT authentication just for fun, beware to use it on production.

Token based authentication with flask-security extension

I am currently looking for a way to secure a REST API using token based authentication. I am developing the API in Python using Flask and have discovered the flask-security extension which seems to have a lot of interesting features.
One of the features mentioned in the documentation is Token Authentication.
According to the documentation:
Token based authentication is enabled by retrieving the user auth
token by performing an HTTP POST with the authentication details as
JSON data against the authentication endpoint. A successful call to
this endpoint will return the user’s ID and their authentication
token. This token can be used in subsequent requests to protected
resources.
I am however still a bit confused on how to implement this feature using flask-security.
Some online research has led me to using things such as #auth_token_required but I am having some trouble to put everything together. The flask-security documentation itself is not very helpful.
For example, how can a user get an authentication token? what is the authentication endpoints?
It would be great if you could lead me in the right direction. Code examples would be awesome too :-)
Endpoint is /login, you post your credentials as json request body:
{'email':'john#smit.com', 'password':'1234'}
However for this to work you need to disable the csrf tokens in your flask app (thanks Mandar Vaze):
app.config['WTF_CSRF_ENABLED'] = False
Then you do each request with the token in the HTTP headers:
Authentication-Token:WyI1NTE1MjhmNDMxY2Q3NTEwOTQxY2ZhYTgiLCI2Yjc4NTA4MzBlYzM0Y2NhZTdjZjIxNzlmZjhiNTA5ZSJd.B_bF8g.t1oUMxHr_fQfRUAF4aLpn2zjja0
Or as query string:
http://localhost:5000/protected?auth_token=WyI1NTE1MjhmNDMxY2Q3NTEwOTQxY2ZhYTgiLCI2Yjc4NTA4MzBlYzM0Y2NhZTdjZjIxNzlmZjhiNTA5ZSJd.B_bF8g.t1oUMxHr_fQfRUAF4aLpn2zjja0
Client example in python 3:
import requests
import json
#do the login
r = requests.post('http://localhost:5000/login',
data=json.dumps({'email':'john#smit.com', 'password':'1234'}),
headers={'content-type': 'application/json'})
response = r.json()
print(response) #check response
token = response['response']['user']['authentication_token'] #set token value
#Now you can do authorised calls
r = requests.get('http://localhost:5000/protected',
headers={'Authentication-Token': token})
print(r.text)
Angular example snippet to obtain the token:
$http.post('/login', {"email": $scope.formdata.login,"password":$scope.formdata.password}).
success(function(results) {
$window.sessionStorage.token = results.response.user.authentication_token;
});
Angular example snippet to visit protected pages:
if ($window.sessionStorage.getItem('token')) {
config.headers['Authentication-Token'] = $window.sessionStorage.getItem('token');
}
I found Flask-Security's token-based not a good candidate for my project. I recommend using JWT token instead.
The problems with Flask-Security's token based authentication.
Need to disable CSRF globally, this is not good when you also have a traditional web application in which CSRF token is desirable
No easy way to renew the token ( without submitting password again )
Can not control the payload of the token, there's no API to put/get data to/from the token
That token, by design, only works with one Flask app. So if your frontend app needs to talk with multiple restful apis, this wont work well
Check out JWT (pyjwt or flask-jwt) token, it solves all the above problems and more.
Authentication endpoint is /login
Look at the code of flask-security here specifically views.py: _render_json()
login() calls _render_json which in turn calls get_auth_token() - and returns the auth token.
Problem (for me) is to get this to work.
For me request.json seems empty (hence this does not work)
{"email": "test#example.com", "password": "test123"}
Hopefully this helps you move forward a little.

Nodejs - ADAL package issue

I am using adal-node package in my Nodejs app for authenticating against Azure AD.
URL: https://www.npmjs.org/package/adal-node
I am using acquireTokenWithAuthorizationCode method to get the token and it works fine.
When my auth code expires, I want to refresh my token using the below.
authenticationContext.acquireTokenWithRefreshToken(_tokenData.refreshToken, authdata.clientId, authdata.resource, callback).
But when I run this code, its giving me the below error.
"Get Token request returned http error: 400 and server response: {"error":"invalid_request","error_description":"AADSTS90014: The request body must contain the following parameter: 'client_secret or client_assertion'
The method will not accept client secret as its argument, but still it complains that it needs a client secret.
Can you please help?
Thanks
Anil
Unfortunately, the library does not support your scenario right now. The function acquireTokenWithRefreshToken that you are using was intended for OAuth public clients that don't require a client secret, but your app is an OAuth confidential client which does.
I have filed the following issue in the GitHub repo to track the need to add a new method that would support your scenario.
https://github.com/AzureAD/azure-activedirectory-library-for-nodejs/issues/22

Resources