This guide shows you all the steps to build an Angular SPA with a focus on authentication. The single-page web application uses Sign-In with google and angularx-social-login. The .NET Core authentication backend creates asymmetrically signed tokens to access another REST-API. The sample is fully working and can be the basis for a microservice-like architecture.
Authentication workflow and involved components:
Background and Structure of this Guide
When I wanted to create this kind of application I found many descriptions showing some part of it. This guide brings the parts together. It is structured so you can optionally test every step before continuing to the next.
This guide focuses on the key aspects. I link to other articles for details and download locations of the tools. I use Visual Studio Community for ASP.NET Core 3.1 development.
Contents
Create the Angular App
Add the Login Functionality
Authentication API in the .NET Core Backend
Use the Authentication API
Use the Access Token to Call the Service API
Final Thoughts and Outlook
1. Create the Angular App
Download and install Node.js/NPM.
Create the folder C:\dev
and open a command prompt.
Install Angular (I used Angular 9 when writing this guide):
C:\dev>npm install -g @angular/cli
Create the app:
C:\dev>ng new SampleAuthentication
Install the angularx social login module
C:\dev>npm install angularx-social-login
(Optional) Test the app
Start the app and open it in your browser to see if everything is working:
C:\dev>ng serve
Further reading: Understanding Angular and Creating Your First Application
2. Add the Login Functionality
Get a client ID from google
Create a configuration for your app in the google developer console. And add the URL of the Angular debug server (http://localhost:4200) as “Authorised JavaScript origin”:
Get the app’s Client ID that google created for you. Copy the client ID. You will need it in further steps of this guide.
Configure the social login module
Use your google client ID and activate the social login module in the providers section of the app.module.ts:
The code above also adds the HttpClient module, which will be needed later in this guide.
Further reading: Google authentication in Angular
Create the Login Code
Edit app.component.ts
Edit app.component.html
(Optional) Test the login
Start the app
c:\dev>ng serve
Open the app URL in your browser, click “Sign in with google” to open the login dialogue. Sign in with your google credentials:
You are now logged in:
Use the debugger of the chrome browser to get the idToken and other information:
Google creates a new idToken on every login. The token is only valid for a short time.
Copy the idToken. You will need it in the next step of this guide if you want to manually test the API.
3. Authentication API in the .NET Core Backend
The authentication API will use the idToken from google and verify it. Then it creates an access token that grants access to the other APIs of your app.
You will have to increase security before you run this code in a production environment: Shorter token lifetime and refreshs, maybe use sessions instead of tokens, etc.
Install Visual Studio Community (it’s free) with the ASP.NET and web development workload. Create an ASP.NET Core Web API project.
Verification of the idToken
Use the Visual Studio package manager to install the google Auth Package:
Install-Package Google.Apis.Auth
Create an API to verify the idToken.
Change the value in settings.Audience
to your google client ID, that you created in the first step of this guide:
The call to GoogleJsonWebSignature.ValidateAsync
will throw in case of an error. The Authenticate
method uses the JwtGeneratorclass
to create and return a custom access token.
Create Custom Access Tokens in .NET Core Using Asymmetric Signatures
With asymmetric JWT signing, only the authentication service knows the private key. The authentication service uses the private key to sign the access token and other APIs use only the public key to verify the access token.
Add the JwtGenerator
class, that generates the token:
The JwtGenerator uses the private key, that it gets passed from the UserController. Add the key to appsettings.json, where the UserControler reads it from.
You can use my private key for testing but you will have to create your own private-public key pair for production use. You will also have to adjust token lifetime, etc. for production use.
*Further reading: JWT Authentication with Asymmetric Encryption using certificates in ASP.NET Core. *This story also shows how to create your own public-private key pair.
Edit Startup.cs, which configures the ASP.NET Core backend to use the config, allow access from the Angular client, etc.:
4. Use the Authentication API
Configure the .NET Core API project in debug mode on HTTPS port 5001:
Start the authentication API in Visual Studio:
(Optional) Manually access the authentication API
Use postman to access the API at: https://localhost:5001/user/authenticate
Post the idToken, that you copied from the Chrome debugger in the second step of this guide:
Call the authentication API from the app
Use the Angular HttpClient to post the idToken to the authentication API. Modify app.component.ts:
Line 5: Import the HttpClient
Lines 21: Send the idToken
(Optional) Test the workflow in the app
Do the same as in the first step of this guide.
Start the app
c:\dev>ng serve
Login and use the debugger and logging in the chrome browser to verify that calling the backend and receiving the generated access token is working:
Copy the access token if you want to do a manual test in the next step of this guide.
5. Use the Access Token to Call the Service API
The access token from the authentication API will grant access to this new service API.
Create an ASP.NET Core Web API project and configure it in debug mode on HTTPS port 5002:
Add a controller:
Edit Startup.cs. It took me a while to configure the validation of the token. The public key to the corresponding private key of the authentication API is used to validate the token. The hard part was to inject the public key. See the comments in the source code for details:
(Optional) Use postman to access the service API
Use postman to access the service API via HTTP GET at: https://localhost:5002/secured
In the previous part of this guide, you copied the access token in the Chrome debugger. Add it as bearer token to the call:
The Final step of this guide: Use the app to access the service API
Modify app.component.ts to post the access key to the service API:
You successfully accessed the protected service API:
6. Final Thoughts and Outlook
Your app is now fully working! But it is only a sample application and you will have to clean up the code and apply security best practices, maybe use a more secure OAuth flow, use Angular and .NET Core design patterns, error handling, etc. to use it in production. And you need your own private-public key pair (see JWT Authentication with Asymmetric Encryption using certificates in ASP.NET Core by
Eduard Stefanescu).
You can add other providers like facebook or your own account database.
See also my follow-up stories:
- How to use NSwag to autogenerate the TypeScript client to access the .NET Core service API and use OpenAPI/Swagger to describe the API
- How to deploy the .NET Core API and Angular App as Microservices to Kubernetes using Ingress and develop local using Docker Desktop
Please contact me if you have any questions, ideas, or suggestions.
Top comments (3)
Hey Christian, thanks for the great write-up!
I was able to follow along easily and understood it well. I do have a few questions though that maybe you could answer if you have some time?
Is it recommended to have a separate authentication service API? I'm familiar with microservices architecture, but for a project small enough, is it a good idea to create the authentication flow in that singular API?
Should we initiate it social authentication from the client always or could I do it from the backend API? Say I just place a button on the frontend, "Sign In with Google" which just calls an API method on the backend to initiate the auth flow. How would that work? I'm thinking of doing this so that I can keep all the ClientID and Client Secret (for Google, Facebook, Spotify, etc.) hidden away from the client and tucked away somewhere safe in my backend server/secret vault.
Hello Aakash,
Thank you for your feedback.
I will try to answer your questions. But these are only my personal oppinions so you should do your own researches, too.
I would use a single microservice that handles everything regarding users and authentication. Like login with google, facebook, (optional) user signup and user database, creation of application JWTs. etc
From a security perspective there is no reason to hide the clientID from the user. But handling the flow in the backend would be a security improvement for other reasons. The OAuth flow in the backend is called "Authorization Code Flow" and it will be more secure. But I did not try it myself yet.
Thanks for your article. Good trick to set audience , because a lot of people forget to check it.
btw i like the schema that in first image , it is very helpful.