Here's the solution I used:
1) There are 2 authentication levels
- Ionic app
- API
2) When the user logs in the app I use Firebase authentication, which returns a token to me if everything is ok. At this point the user is authenticated on the app and I save the token for the call to the API.
3) When the user needs access to any resource, there will be a call to the API. This call will need some sort of authentication too, because the API is not public.
4) I get the token I saved on (2) and I put it in the header of my http request:
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Authentication', `${my-saved-token}`);
let options = new RequestOptions({ headers: headers });
return this.http.get(url, options)
.toPromise()
.then( .... )
5) On server side (I'm using ASP.NET Core), I created a custom middleware which reads the header of every request and looks for the 'Authentication' key. If it's not there, it just return 401 error, otherwise it validates the token, and if it's valid, it sends the request to the next middleware in the pipeline. The validation service is not shown here, but I used the code on this answer: Firebase authentication asp.net core
public class AuthenticationValidatorMiddleware
{
private readonly RequestDelegate _next;
private ITokenValidation TokenValidator { get; set; }
public AuthenticationValidatorMiddleware(RequestDelegate next, ITokenValidation tokenValidator)
{
_next = next;
TokenValidator = tokenValidator;
}
public async Task Invoke(HttpContext context)
{
if (!context.Request.Headers.Keys.Contains("Authentication"))
{
context.Response.StatusCode = 400; //Bad Request
await context.Response.WriteAsync("Authentication is missing");
return;
}
else
{
var token = context.Request.Headers["authentication"];
if (!TokenValidator.Validate(token))
{
context.Response.StatusCode = 401; //UnAuthorized
await context.Response.WriteAsync("Invalid authentication");
return;
}
}
await _next.Invoke(context);
}
}
On client app I used AngularFire2 to do the authentication, but bear in mind that when using Firebase + AngularFire2 there's no support in Ionic 2 for the login methods offered by them.
To solve this you have to use cordova-plugin-inappbrowser
and cordova-plugin-facebook4
. Then you'll log in the app via Facebook plugin, get the Facebook authentication token and then use this token to log in Firebase. Here's my signin method:
public signInWithFacebook(): firebase.Promise<any>
{
if (this.platformService.is('cordova'))
{
return Facebook.login(['email', 'public_profile']).then(res =>
{
const facebookCredential = firebase.auth.FacebookAuthProvider.credential(res.authResponse.accessToken);
return firebase.auth().signInWithCredential(facebookCredential);
});
}
else
{
return this.firebaseAuthenticationService.login(
{
provider: AuthProviders.Facebook,
method: AuthMethods.Popup
});
}
}
As you can see in the code above, if I detect that I'm running on browser, I use the native AngularFire2 authentication, if I'm running on a device, then I log in via the Facebook cordova plugin, the the credentials and then pass it to Firebase.
The answer is big but I hope I could made myself clear... if you have any further questions, please ask...