User authentication and authorization can be difficult and time consuming. Getting it wrong can also have disastrous consequences, such as malicious users accessing and stealing personal or sensitive information from your app.
Unless you are a large organisation that can afford to spend lots of time on developing a bespoke authentication/authorization system, it is often best to make use of existing solutions to streamline your development process and give you peace of mind.
Auth0 is one such solution, and could be called Authentication as a Service (AaaS) or Identity as a Service (IDaaS). In short, it is a complete user management system that can be used to authenticate requests to your application. It has plenty of built in features that you would expect from modern authentication, such as social login (Google, Facebook, etc.), Single Sign On (SSO), and Multi-Factor Authentication.
Below is a diagram outlining the basics of how authentication works using Auth0.
I have created a GitHub repository for this tutorial. Please find it here.
If you don't already have an Auth0 account, go ahead and create one here.
Log in to you Auth0 account and go to the Applications tab. Click on Create Application and create a new Single Page Web Application.
Go to the settings tab of your newly created application and make note of the Domain and Client ID - we will need these later.
On the same page scroll down to Application URIs and fill in the following fields:
NOTE: http://localhost:3000 is the default URL of the Nuxt app. If you are using a different port, change the above values accordingly.
Make sure that you Save Changes.
Next we need to tell Auth0 about our API. Go to APIs and click Create API. Fill in a Name and an Identifier, then click Create. Make a note of the Identifier as we will need this later.
And that's it for the Auth0 configuration! Next let's move on to creating our API with ASP.Net Core.
Start by creating a new ASP.NET Core API project using the Visual Studio project templates (Create a new project -> ASP.NET Core Web Application -> API).
You will need the following NuGet packages installed:
Microsoft.AspNetCore.Authentication.JwtBearer
Microsoft.AspNetCore.Authentication.OpenIdConnect
NOTE: These packages were installed by default using the .NET 5.0 project template, but I believe these will need to be installed manually if you are using .NET Core 3 .
In order to validate access tokens against Auth0, our API needs to know the Domain and Identifier values that we got from Auth0 earlier. I've opted to save these using User Secrets for added security.
Navigate to the APIs project folder and run the following commands:
dotnet user-secrets init
dotnet user-secrets set "Authentication:Auth0:Authority" "MyDomain"
dotnet user-secrets set "Authentication:Auth0:Audience" "MyIdentifier"
Next we need to configure the Startup class. In the ConfigureServices method, add the following lines of code:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
var auth0Authentication = Configuration.GetSection("Authentication:Auth0");
options.Authority = auth0Authentication["Authority"];
options.Audience = auth0Authentication["Audience"];
});
This configures ASP.NET Core to authenticate using a JWT Bearer and verify it against Auth0 using the values we just save in User Secrets.
We also need to add a few line of code to the Configure method. Since order is very important in order to configure the middleware pipeline properly, I'll just paste the whole method:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseCors(builder =>
{
builder
.WithOrigins("http://localhost:3000")
.AllowAnyMethod()
.AllowAnyHeader();
});
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Here we are adding a CORS policy to allow requests to the API from our Nuxt app (which is served by default on http://localhost:3000). Secondly, we are calling app.UseAuthentication(), which will tell the app to use the authentication middleware, using the configuration we added in the ConfigureServices method.
The final thing we need to do is decide which controllers/actions we want to protect. If you created your project from the Visual Studio template, you should already have a WeatherForecastController. I'm just going to protect the whole controller, by adding the [Authorize] attribute to the top of the controller.
...
[Authorize]
public class WeatherForecastController : ControllerBase
{
...
To get started with creating the Nuxt client, run:
yarn create nuxt-app my-app-name
And just go with the default options.
We then need to install a couple of Nuxt modules. Navigate to the root directory of the Nuxt project (should contain `package.json`) and run the following command.
yarn add @nuxtjs/axios @nuxtjs/auth @nuxtjs/dotenv
This will install Axios (which we will use to make requests to our API), the Auth module (which simplifies managing authentication on the Nuxt client), and the Dotenv module (which allows us to save our secret Auth0 values in a .env file).
Next create a .env file in the root directory of your Nuxt project and add the following lines (substituting in your Auth0 values):
AUTHENTICATION_AUTH0_DOMAIN=MyDomain
AUTHENTICATION_AUTH0_CLIENT_ID=MyClientID
AUTHENTICATION_AUTH0_AUDIENCE=MyIdentifier
Next we move on to configuring Nuxt my making some changes to the nuxt.config.js file. First we will tell Nuxt simply to use the module that we just installed using by adding the following lines:
buildModules: [
'@nuxtjs/dotenv'
],
modules: [
'@nuxtjs/axios',
'@nuxtjs/auth',
],
Then we'll configure Axios to have a base URL pointing to our API. In my case, the port was 44363, but this may well be different for your project.
axios: {
baseURL: 'https://localhost:44363'
},
The next lines of configuration tell the Nuxt router to use the Auth module as middleware. This means that before the user navigates to any page, the Auth middleware will check that the user is authenticated (and if not redirect to the login page). This configuration will protect all routes in your client app. However, there are ways to only protect specific routes, if you so wish.
router: {
middleware: ['auth'],
},
Finally we will configure the Auth middleware to read the secret Auth0 values from the .env file, and store it in a strategy called auth0.
auth: {
strategies: {
auth0: {
domain: process.env.AUTHENTICATION_AUTH0_DOMAIN,
client_id: process.env.AUTHENTICATION_AUTH0_CLIENT_ID,
audience: process.env.AUTHENTICATION_AUTH0_AUDIENCE
}
}
}
And that's it for nuxt.config.js. The final bit of configuration we need to do is to create an empty index.js file inside the store directory. This is because the Auth middleware uses the Nuxt store to store authentication information, and in Nuxt the store file must exist (but can be empty) in order to activate the store.
The final thing that we need to do is create a couple of pages. We will start by creating a basic index page that simply tries to get the weather forecast list from our API and display it on the page. This will be a protected page, so when we are not logged in, we will be redirected to login. It's also important to note that API is also protected, so even if a user managed to gain access to the index page when not authenticated, the API would still refuse to send the data. This is an important principal in web app design - no matter how much protection you put on the front end, the backend API should still be protected and verify everything the user sends, since it is possible for a malicious user to modify anything that comes from the frontend.
// pages/index.vue
<template>
<div>
<h1>Weather Forecast</h1>
{{ response }}
</div>
</template>
<script>
export default {
data() {
return {
response: []
}
},
async mounted() {
this.response = await this.$axios.$get('weatherforecast')
}
}
</script>
And the login page will simply contain a button that redirects us to the Auth0 login screen. Since we configured the auth0 strategy for our Auth module, the loginWith('auth0') method knows where to send our request.
// pages/login.vue
<template>
<div>
<h1>Login</h1>
<button @click="onClick">Login with Auth0</button>
</div>
</template>
<script>
export default {
methods: {
onClick() {
this.$auth.loginWith('auth0')
}
}
}
</script>
And that's it! Try running both the API and the Nuxt client projects and navigate to the base URL of the Nuxt project (http://localhost:3000). You should automatically be redirected to the login page.
Clicking the button should redirect you to the Auth0 sign in page.
Sign in with whichever method you have configured for Auth0. If sign in is successful, you will be redirected back to the index page of your Nuxt app. Since you are now logged in, when the client requests the weather forecast from the API, it will also send along with the request the Auth0 Bearer token. The API will then check the token against Auth0 and return the weather forecast object.
In this post, I showed you how to protect a Nuxt client app and a ASP.NET Core API with Auth0 in a few simple steps. Using Auth0 is a great way to add authentication to your apps without any or the hassle of developing your own authentication management system.
Please feel free to check out the completed project in my GitHub repo.
Since it's almost Christmas, you could also check out my Top Christmas Gifts To Buy A Developer post that was featured on Hashnode recently.
I post mostly about full stack .NET and Vue web development. To make sure that you don't miss out on any posts, please follow this blog and subscribe to my newsletter. If you found this post helpful, please like it and share it. You can also find me on Twitter.
Previously published at https://samwalpole.com/web-app-authentication-using-auth0-aspnet-core-and-nuxtjs