Firebase Authentication (JWT) with .NET Core
Firebase Authentication (JWT) with .NET Core
I'm developing a simple API that handles Authentication made by Firebase - to be used later with Android clients.
So in Firebase console I enabled Facebook and Google sign-in methods and created a sample html page that I can use it to test the login method - this next function is called by a button:
function loginFacebook()
var provider = new firebase.auth.FacebookAuthProvider();
var token = "";
firebase.auth().signInWithPopup(provider).then(function (result)
var token = result.credential.accessToken;
var user = result.user;
alert("login OK");
user.getToken().then(function (t)
token = t;
loginAPI();
);
).catch(function (error)
var errorCode = error.code;
var errorMessage = error.message;
alert(errorCode + " - " + errorMessage);
);
next I use the token and send it to my API with a simple ajax call from jQuery here:
function loginAPI()
$.ajax(
url: "http://localhost:58041/v1/Users/",
dataType: 'json',
type: 'GET',
beforeSend: function (xhr)
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Bearer " + token);
,
error: function (ex)
console.log(ex.status + " - " + ex.statusText);
,
success: function (data)
console.log(data);
return data;
);
Next stop: the API backend - written with .NET Core.
Under the Startup I've configured the JwtBearer Auth (package Microsoft.AspNetCore.Authentication.JwtBearer
):
Microsoft.AspNetCore.Authentication.JwtBearer
app.UseJwtBearerAuthentication(new JwtBearerOptions
AutomaticAuthenticate = true,
IncludeErrorDetails = true,
Authority = "https://securetoken.google.com/PROJECT-ID",
TokenValidationParameters = new TokenValidationParameters
ValidateIssuer = true,
ValidIssuer = "https://securetoken.google.com/PROJECT-ID",
ValidateAudience = true,
ValidAudience = "PROJECT-ID",
ValidateLifetime = true,
,
);
And here is the Controller code - with the [Authorize]
attribute:
[Authorize]
[Authorize]
[Route("v1/[controller]")]
public class UsersController : Controller
private readonly ILogger _logger;
private readonly UserService _userService;
public UsersController(ILogger<UsersController> logger, UserService userService)
_logger = logger;
_userService = userService;
[HttpGet]
public async Task<IList<User>> Get()
return await _userService.GetAll();
The API response is 200 OK (HttpContext.User.Identity.IsAuthenticated
is true
inside the Controller), but I think it shouldn't. My problem is that I'm not entirely sure that this is secure.
HttpContext.User.Identity.IsAuthenticated
true
How this is checking the signature part of the JWT token? I saw a lot of code samples mentioning x509 or RS256 algorithm, where do they fit with this? Shouldn't be checking against some kind of certificate or private key with the IssuerSigningKey
or TokenDecryptionKey
from the TokenValidationParameters
class? What I'm missing?
IssuerSigningKey
TokenDecryptionKey
TokenValidationParameters
Relevant sources of knowledge about the issue:
200 OK
Authorization
app.UseMvc()
app.UseJwtBearerAuthentication()
If I don't pass the
Authorization
header, the the response is 401
. And the app.UseMvc()
is after the app.UseJwtBearerAuthentication()
. I'm just not sure about the security. I tried to hack my app and was not able to. Maybe I'm just paranoid.– Israel Rodriguez
Feb 21 '17 at 13:56
Authorization
401
app.UseMvc()
app.UseJwtBearerAuthentication()
Hmm, but you say the response "shouldn't be 200". Why? Are you intentionally passing an incorrect token in the header? Or why do you expect the response not to be 200?
– Mark Vincze
Feb 21 '17 at 15:58
Since I'm not providing a private key anywhere in my code so I think that shouldn't work, but after being unable to hack it, I think I'm just paranoid.
– Israel Rodriguez
Feb 21 '17 at 17:40
I'm afraid you misunderstand how the token signing works in this flow. Your application is not supposed to provide (or have) a private key (or any kind of key). I added a description of the flow to my blog post: blog.markvincze.com/secure-an-asp-net-core-api-with-firebase/…
– Mark Vincze
Feb 22 '17 at 10:47
3 Answers
3
Firebase uses the RSA256 asymmetric key cryptosystem, which means it has a public and a private key. Signing a token happens with the private key, while verifying a token happens with the public key.
The following diagram illustrates how the token signing happens.
During signing in and accessing a secure endpoint, the following steps are involved.
JwtBearerMiddleware
https://securetoken.google.com/my-firebase-project/.well-known/openid-configuration
Authorization
JwtBearerMiddleware
HttpContext.User
HttpContext.User.Identity.IsAuthenticated
You can find an even simpler description of this concept on the RSA Wikipedia page, and some more information about Firebase + ASP.NET in my blog post.
Thanks for the clarification @Mark
– Israel Rodriguez
Feb 23 '17 at 20:03
Great explanation, thanks :-)
– jhm
Mar 2 '17 at 10:29
@Mark Vincze - Could you perhaps have a look at this question as well (related)? stackoverflow.com/q/42560558/1409779 Would be much appreciated :-)
– jhm
Mar 2 '17 at 16:21
For the backend side, there is a Nuget package that does the trick for you:
Install-Package AspNetCore.Firebase.Authentication
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
app.UseFirebaseAuthentication("https://securetoken.google.com/MYPROJECTNAME", "MYPROJECTNAME");
It does the audience, issuer, signature and validity validation
Not sure this works with ASP .NET Core 2.0. I get the following error: Could not load type 'Microsoft.AspNetCore.Builder.JwtBearerOptions' from assembly 'Microsoft.AspNetCore.Authentication.JwtBearer, Version=2.0.0.0
– Primico
Oct 25 '17 at 1:02
@Raphaël What is ApiKey for?
– Tzvi Gregory Kaidanov
May 21 at 9:56
@TzviGregoryKaidanov actually it's in the appsettings, but unused, as the middleware only validate token & signature, which doesn't require ApiKey
– Raphaël
May 22 at 10:08
@Primico I published a .netcore2.0 compatible package
– Raphaël
May 22 at 10:08
@ Raphaël workes like a charm. Thank you!
– Tzvi Gregory Kaidanov
May 23 at 7:15
The NuGet packet is using the old ASP NET Core 1.x Authentication mechanism
The authentication has been changed: https://docs.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x
Published the package AspNetCore.Firebase.Authentication 2.0 which support .aspnetcore2.0
– Raphaël
May 22 at 10:09
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
The response is
200 OK
even if you don't pass theAuthorization
header? That's definitely wrong. Do you have theapp.UseMvc()
call before or afterapp.UseJwtBearerAuthentication()
?– Mark Vincze
Feb 21 '17 at 8:24