Angular like any other single-page (SPA) application needs to access back-end API to retrieve and update data.
And Azure functions is a popular way to build APIs in Azure.
The question comes then how to secure access to your Azure functions (or Azure API management) in this scenario?
One of the approaches to secure Azure functions is use HttpTrigger AuthLevel attribute.
Example is shows in code snippet below.
The default is AuthorizationLevel.Function which requires a function-specific API key to call a function.
Something like below:
The issue with this approach is that anyone accessing your site can use Developer Tools in browser and see the function code value and therefore invoke your function outside of your application (for example using Postmen or any other development/testing tool), which is probably not desirable.
Secure an HTTP endpoint in production
For production environment Microsoft recommends different form of access control which are documented in Secure an HTTP endpoint in production.
Following options are suggested
Turn on App Service Authentication / Authorization.
Use Azure API Management (APIM) to authenticate requests.
Deploy your function app to an Azure App Service Environment (ASE).
Implementation approaches one can leverage for the first option are described below. Will review remaining options in subsequent blog posts.
Angular Adal Module
Probably one of the easiest ways to call Azure Function protected by App Service Authentication is leveraging Angular Adal module provided by Microsoft. The documentation is very clear and configuration is very simple. Essentially it works "out-of-the-box".
One needs to install the microsoft-adal-angular6 package, import MsAdalModule, configure Adal options, and secure routes using canActivate: [AuthenticationGuard].
Example is shown in snippets below:
1. Initialize in angular-sample\src\app\app.module.ts
2. Protect routes in angular-sample\src\app\app-routing.module.ts:
References and Code samples
Complete documentation is provided at microsoft-adal-angular6 by Microsoft and is pretty good. Would probably be better if examples would not use configuration elements like Client/App ID coded inline and provided a link to the working "Hello World" sample in public git repository.
To cover those requirements and provide end-to-end scenario I've created angular-azure-function-aad example in GitHub. It is build on top of Angular Tour of Heroes App and Tutorial. Hope it will help folks who follow this path.
At the same time OAuth 2.0 Security Best Current Practice does not recommend to use the authorization code grant with Proof Key for Code Exchange (PKCE) to request access tokens from SPAs, as opposed to the original OAuth2 spec proposing use of the implicit grant for that scenario.
Therefore seems microsoft-adal-angular6 is using approach which is no longer recommended.
Fortunately there are other ways we can get access to back-end API described below.
Azure App Service Authentication
One of the possible drawbacks of using Adal Module that the configuration is done in the code.
If we could leverage Azure App Service Authentication configuration we could separate code from Authentication concerns (at the expense of some flexibility). We would have enabled a single Access Control enforcement point (as opposed to having configure it for each route), and greatly help with automation of security audits.
As occurs this is in fact possible but requires more configuration than just enabling App Service Authentication on Angular and Azure Function endpoints. This is still quite simple (once you know what to do) but seems to lack documented step-by-step instructions. I am sure at some point Microsoft will provide end-to-end tutorial and instructions but for now one can use steps below:
Deploy Angular app and Azure function into App Services in Azure.
Create App registration in Azure AD.
Configure Azure App Service Authentication for both Angular and Azure Function App Services using App Registration created in #2. (e.g. Use Azure portal or PowerShell)
Configure secret Angular App Service Authentication.
Update additionalLoginParams in authsettings section of Angular Website config
Configure HttpInterceptor to pass access token to Azure Function
Steps 1-3 below are standard steps required for configuring Authentication for any App Service.
Steps 4. and 5. are less common so below describes the details as well as step 6 where token is actually passed when calling Azure function.
Step 4 - Configure secret Angular App Service Authentication.
To access Azure Function configured with Azure AD authentication we need to provide access token. We use .auth/me endpoint to retrieve access token.
As per Microsoft engineering team when client secret in auth settings is not provided
Step 5 - Update additionalLoginParams in authsettings
At this point access token will be provided but attempt to access Azure function using it as Bearer token still returns 401 (Unauthorized).
As described in the Configure App Service to return a usable access token we make sure the angular app get’s correct access_token.
Use Azure Resource Explorer to set additionalLoginParams in authsettings section of Angular Website config as below.
Step 6 - Configure HttpInterceptor to pass access token to Azure Function
Configure Angular HttpInterceptor to add access token to outgoing requests.
This step is already included in the provided Github sample.
After this our Angular Application configured with EasyAuth can successfully access Azure Function and pass Bearer access token (assuming the are both using the same app registration as described in steps 1-3).
References and Code samples
End-to-end scenario is covered in angular-azure-function-easyauth example in GitHub.
Huge thanks to Elena Neroslavskaya who researched and provided critical information for this implementation and to David Odhiambo for supporting all the way until we found the solution.