My goal is to have Angular 8 SPA with a serverless backend represented by multiple azure function apps using OAuth from Facebook, Google...
I have a problem with calling azure functions on behalf of authorized users. Function sees these calls as anonymous users.
From the browser, function returns authorized user name, from browser app call it returns 'no name' that mean user is not authorized.
My guess is that the session from myapp.azurewebsites.net is not visible in my app that is in the localhost (it can be any other domain). Also, I can't provide session in the request to function endpoint.
So, what is the way to authorize users and call azure functions from the client app in other domain? Or it is possible only with the manual implementation of JWT tokens with spreaded logic across all functions? Also, I do not want to pay to third-party services like Auth0 or even AAD.
Jim Xu, suggested a way that works, but not for my case. Disadvantages I see:
I am looking for answers to such questions:
My code sample and configurations:
Here is a client app main parts I am using to call:
<button (click)="call('https://myapp.azurewebsites.net/Function1')">CallWithoutAuth</button>
<button (click)="call('https://myapp.azurewebsites.net/Function2')">CallWithAuth</button>
<a href="https://myapp.azurewebsites.net/.auth/login/facebook?post_login_redirect_url=http%3A%2F%2Flocalhost%3A5000" target="_blank">Log in with Facebook</a>
Body of call function:
var url = 'my azure func url with auth via facebook';
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
}
};
xhttp.onerror = function(e){console.log(e, this)};
xhttp.open("GET", url, true);
xhttp.send();
Function code:
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "Func2")] HttpRequest req,
ClaimsPrincipal claimsPrincipal)
{
var name = claimsPrincipal?.Identity?.Name;
return (ActionResult)new OkObjectResult($"Hello, {name ?? "no name"}");
}
Here are functions app configs:
CORS config:
Fasebook config:
According to my test, we can use the following steps to call the Azure function projected by facebook
Integrate Facebook into your angular application. after doing that, we can login facebook and get a accessToken
. For more details about how to implement it, please refer to the article.
For example
a. add the application URL into Valid OAuth Redirect URIs
b. add the following code in app.component.ts
export class AppComponent {
title = 'web';
fbLibrary() {
(window as any).fbAsyncInit = function() {
window['FB'].init({
appId : '<app id you use to project azure function>',
cookie : true,
xfbml : true,
version : 'v3.1'
});
window['FB'].AppEvents.logPageView();
};
(function(d, s, id){
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
js.src = "https://connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
}
ngOnInit() {
this.fbLibrary();
}
login() {
window['FB'].login((response) => {
if (response.authResponse) {
//get access token
var accessToken=response.authResponse.accessToken;
console.log('login response',accessToken);
window['FB'].api('/me', {
fields: 'last_name, first_name, email'
}, (userInfo) => {
console.log("user information");
console.log(userInfo);
});
} else {
console.log('User login failed');
}
}, {scope: 'email'});
}
}
c. add login button to html
Call the following request to exchange this accessToken for an 'App Service Token'
Request
POST https://<appname>.azurewebsites.net/.auth/login/aad HTTP/1.1
Content-Type: application/json
{"access_token":"<token>"}
Response
{
"authenticationToken": "...",
"user": {
"userId": "sid:..."
}
}
Get https://myapp.azurewebsites.net/Function1
X-ZUMO-AUTH: <authenticationToken_value>
For further information, please refer to https://learn.microsoft.com/en-us/azure/app-service/app-service-authentication-how-to.