0
votes

This question is based on the example code provided by Microsoft:
https://docs.microsoft.com/en-us/samples/azure-samples/active-directory-javascript-singlepageapp-angular/active-directory-javascript-singlepageapp-angular/

app.module.ts has been configured and the application can successfully login through the Azure B2C sign in screen.

There is also an Azure function that simply returns a JSON object with one string property "text" through an HTTP GET request. The function has been configured to authenticate using Azure B2C. This has been confirmed by visiting the function URL in the browser, logging in through the B2C login screen, and being returned the JSON object from the function.

The component that is calling the protected api looks like this:

import { Component, OnInit } from '@angular/core';
import { MsalService } from '@azure/msal-angular';
import { HttpClient } from '@angular/common/http';

const FUNCTION_ENDPOINT = 'function-url-here';

export interface MyInterface {
  text: string;
}

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

  value: MyInterface;

  constructor(private authService: MsalService, private http: HttpClient) { }

  ngOnInit() {
    this.getValue();
  }

  getValue() {
    this.http.get<MyInterface>(FUNCTION_ENDPOINT).toPromise()
      .then(value => {
          this.value = value;
      });
  }

}

When the function authentication is turned off, the JSON from the function is returned to the Angular app. When the function authentication is turned on, following error is printed to the browser console:

Access to XMLHttpRequest at 'https://mytenant.b2clogin.com/mytenant.onmicrosoft.com/oauth2/v2.0/authorize?response_type=id_token&redirect_uri=https%3A%2F%functionname.azurewebsites.net%2F.auth%2Flogin%2Faad%2Fcallback&client_id=SAMPLE-STRING&scope=openid+profile+email&response_mode=form_post&p=b2c_1_signupsignin1&nonce=SAMPLE-STRING&state=redir%3D%252Fapi%252FHttpTrigger2%253Fcode%SAMPLE-STRING' (redirected from 'https://functionname.azurewebsites.net/api/HttpTrigger2?code=SAMPLE-STRING') from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

The second error:

core.js:4002 ERROR Error: Uncaught (in promise): HttpErrorResponse: {"headers":{"normalizedNames":{},"lazyUpdate":null,"headers":{}},"status":0,"statusText":"Unknown Error","url":"https://functionname.azurewebsites.net/api/HttpTrigger2?code=SAMPLE-STRING","ok":false,"name":"HttpErrorResponse","message":"Http failure response for https://functionname.azurewebsites.net/api/HttpTrigger2?code=SAMPLE-STRING: 0 Unknown Error","error":{"isTrusted":true}}

There is also a warning in the console:

Cross-Origin Read Blocking (CORB) blocked cross-origin response https://mytenant.b2clogin.com/mytenant.onmicrosoft.com/oauth2/v2.0/authorize?response_type=id_token&redirect_uri=https%3A%2F%2Ffunctionname.azurewebsites.net%2F.auth%2Flogin%2Faad%2Fcallback&client_id=SAMPLE-STRING&scope=openid+profile+email&response_mode=form_post&p=b2c_1_signupsignin1&nonce=SAMPLE-STRING&state=redir%3D%252Fapi%252FHttpTrigger2%253Fcode%SAMPLE-STRING with MIME type text/html. See https://www.chromestatus.com/feature/5629709824032768 for more details.

The URL for the Angular application is http://localhost:4200/. Here is the CORS configuration for the Azure Function:

enter image description here

enter image description here

What can be done to allow the Angular application to make authenticated requests for the Azure Function?

2
Hi @craydon. You might have to check Enable Access-Control-Allow-Credentials for this.Chris Padgett
What is the difference? Is that secure? If that doesn't work, any other suggestions?crayden
To access the authentication enabled app service, you need to pass the access token in the header. codemilltech.com/…Tony Ju
Was able to add B2C to the function app, but it is not simple to call from Angular using MSAL.crayden

2 Answers

1
votes

AAD and AAD B2C do not support CORS as stated in the MSDN documentation. That means when your Angular app calls the Function API without a token and thus gets redirected to the AAD B2C endpoint for authentication you have an unresolvable problem. The trick with the so-called "implicit flow" is to prevent that by assuring you first have a token issued in a direct call from the Angular app to the B2C endpoint. And because the app registration where this token is assigned for has the permission to access the Function API, the token can be implicitly generated and forwarded to the Function API which then accepts it. And then no redirect occurs and thus no CORS issues as well.

Often - at least from my experience - the CORS problem you encounter is a bit misleading as it shadows the real problem which may be 1) user is not authenticated at all (token is completely missing) or 2) the token for the API call is not implicitly generated and injected to the HTTP call. I propose the following checks:

  1. MsalModule correctly configured (note: the MsalModule.forRoot(<config>) does not support dynamic configurations)
  2. User token is available in SessionStorage or LocalStorage without errors
  3. Implicit flow is configured correctly with:
    • MsalInterceptor registered as provider
    • protectedResourceMap is configured for the Function's URL

I recently created and documented a reference solution with Angular & Azure Function connected to AAD B2C. Source and readme you find here: https://github.com/garaio/DevCamp-AzureServerless/tree/master/Solutions/D04-AAD-B2C-multi-tenancy#client-app-deployment.

0
votes

You can get the access token by referring to this document. Remember to update the protectedResourceMap to your value. For B2C, it should be something like

protectedResourceMap: {"https://tonyb2ctest.onmicrosoft.com/test", ["user_impersonation"]}

Then you can call the function api with the access token.

enter image description here