In this article, we are going to learn how we can implement Angular JWT authentication and authorization. We are going to see how we can securely transfer the user’s credentials from a browser to a server and vice versa.
VIDEO: ASP.NET Core Authentication with JWT and Angular - Part 2.
This part is the continuation of the previous part where we have covered the JWT authentication backend side. In this part, we are going to consume that Web API and implement Angular JWT authentication to secure our pages and add a token to our HTTP requests. Furthermore, in the next article, we are going to learn how to refresh the token generated from our API.
So, let’s start.
Enabling Cross-Origin Requests (CORS)
By default, we can’t send an HTTP request to servers of a different origin due to browser security concerns.
So, what can we do?
We need to configure the server to receive cross-origin requests. By default, the ASP.NET Core application will reject any request coming from the cross-origin clients. To enable CORS in .NET Core Web API, we need to implement a middleware in the Program
class.
Let’s open our JwtAuthentication.Server start project (you may find it in here) and add the code to configure the CORS policy:
builder.Services.AddCors(options => { options.AddPolicy("EnableCORS", builder => { builder.AllowAnyOrigin() .AllowAnyHeader() .AllowAnyMethod(); }); });
To make this middleware available for the application, we have to add one more line above the UseAuthentication
method:
app.UseCors("EnableCORS");
We can find out more about CORS and the additional options to configure it on this location: Enabling CORS in ASP.NET Core.
Perfect.
At this point, the server is ready to listen to the cross-origin requests.
The Login Component for the Angular JWT Authentication
We have created the Angular starter application (available for download from here) which contains all the necessary code (basic Angular components and the routes) we need for this post. With this project, it is going to be much easier to follow along with this post, because we can focus only on the parts important for the Angular JWT authentication. To find out in detail how to work with Angular, visit our Angular Series.
Before we start with the login implementation, we are going to create a new _interfaces
folder, and inside a new login.model
file:
export interface LoginModel { username: string; password: string; }
And then one more, to accept the response from the server with a token:
export interface AuthenticatedResponse{ token: string; }
Next, to implement the login, we are going to modify the LoginComponent
:
export class LoginComponent implements OnInit { invalidLogin: boolean; credentials: LoginModel = {username:'', password:''}; constructor(private router: Router, private http: HttpClient) { } ngOnInit(): void { } login = ( form: NgForm) => { if (form.valid) { this.http.post<AuthenticatedResponse>("https://localhost:5001/api/auth/login", this.credentials, { headers: new HttpHeaders({ "Content-Type": "application/json"}) }) .subscribe({ next: (response: AuthenticatedResponse) => { const token = response.token; localStorage.setItem("jwt", token); this.invalidLogin = false; this.router.navigate(["/"]); }, error: (err: HttpErrorResponse) => this.invalidLogin = true }) } } }
We have two properties. The invalidLogin
where we store whether the login action was successful or not and the credentials
to fetch user credentials from the form.
Inside the login
function, we check if the form is valid and if it is, we send a POST request to the API’s login
endpoint. Here, as a response, we accept an object of the AuthenticatedResponse
type (the one we return from the API’s Login action), which contains the token
property.
The server is going to validate the data. If the username and password are valid, the server will issue a JSON web token and send it back to the browser.
When we accept the response, we extract the token, store it in storage, set invalidLogin
to false, and navigate to the home page. In the case of the error response, we just set invalidLogin
to true.
Once we have the token persisted in storage, we can use it for future calls to access the protected resources on the server. You can think of a token as a special identity card that you may use to access the secret resources in your organization.
Creating Login Form
The first thing we have to do is to import the FormsModule inside the app.module
file:
import { FormsModule } from '@angular/forms'; ... @NgModule({ declarations: [ ... ], imports: [ BrowserModule, AppRoutingModule, HttpClientModule, BrowserAnimationsModule, FormsModule ],
We need it in order to enable the template-driven form and binding.
Next, let’s continue with the login form implementation in the login.component.html
file:
<div class="container"> <form #loginForm="ngForm" (ngSubmit)="login(loginForm)"> <h2 class="form-signin-heading">Login</h2> <div *ngIf="invalidLogin" class="alert alert-danger">Invalid username or password.</div> <br/> <label for="username" class="sr-only">Email address</label> <input type="email" id="username" name="username" [(ngModel)]="credentials.username" class="form-control" placeholder="User Name" required> <br/> <label for="password" class="sr-only">Password</label> <input type="password" id="password" name="password" [(ngModel)]="credentials.password" class="form-control" placeholder="Password" required> <br/> <button class="btn btn-lg btn-primary" type="submit" [disabled]="!loginForm.valid">Log in</button> </form> </div>
This is a simple template-driven form where we store the form value inside the #loginForm
reference and pass it to the login
function. Also, with [(ngModel)]
we bind the values of the input fields to each property inside the LoginModel
object.
Implementing Home Component and the Logout Function
Implementing the logout function is very simple. It’s similar to losing the identity card. If we don’t have the card, we are not able to access the secretly protected resources. To log out the user, we are simply going to delete the token stored in the local storage which is the only key to access protected resources.
If we don’t have the token, the server simply doesn’t know our identity and it’s going to reject our calls to the protected resources. To implement log out we are going to create the logout
function in the HomeComponent
:
isUserAuthenticated = (): boolean => { return false } logOut = () => { localStorage.removeItem("jwt"); }
Inside the logout method, we just remove the token from the local storage. Also, we have the isUserAuthenticated
function, which we will use later on. For now, it only returns false.
Now, let’s modify the template file:
<h1>Home Page</h1> <br> <div *ngIf="isUserAuthenticated()" style="color:blue;"> <h2> YOU ARE LOGGED IN </h2> </div> <br> <ul> <li><a routerLink="/customers">Customer</a></li> <li *ngIf="!isUserAuthenticated()"><a routerLink="/login">Login</a></li> <li *ngIf="isUserAuthenticated()"><a class="logout" (click)="logOut()">Log out</a></li> </ul>
At this point our logout functionality is complete.
Using Angular Jwt Library With Angular JWT Authentication
We are going to use the @auth0/angular-jwt
library, to help us with JWT validation and with adding the token to the HTTP requests.
So, let’s install it first:
npm i @auth0/angular-jwt
Next, let’s configure it by modifying the app.module.ts
file:
... import { FormsModule } from '@angular/forms'; import { JwtModule } from "@auth0/angular-jwt"; ... export function tokenGetter() { return localStorage.getItem("jwt"); } @NgModule({ declarations: [ ... ], imports: [ ... FormsModule, JwtModule.forRoot({ config: { tokenGetter: tokenGetter, allowedDomains: ["localhost:5001"], disallowedRoutes: [] } }) ], providers: [AuthGuard], bootstrap: [AppComponent] }) export class AppModule { }
We inject the JwtModule
and configure it to use the tokenGetter
function to retrieve the token from the local storage and to include it into any Http request executed by the HttpClientModule.
Additionally, we add the server’s URI to the allowed domain list required by JwtModule.
For additional information about this library, you can visit @auth0/angular-jwt.
Protecting Angular Routes with Guards
Protecting the Angular routes is a crucial part of implementing security in the Angular application. To protect the routes, Angular provides the CanActivate
interface. This interface exposes the canActivate
method which we can implement to provide a route guard. The canActivate
method triggers before the Angular route activates, it acts as a guard to the Angular routes. Inside the canActivate
method, we can write any custom logic to protect our routes.
That said, in the guards
folder, we can find the auth.guard.ts
file. Let’s implement the AuthGuard
logic which provides a custom implementation of the CanActivate
interface:
import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; import { JwtHelperService } from '@auth0/angular-jwt'; @Injectable({ providedIn: 'root' }) export class AuthGuard implements CanActivate { constructor(private router:Router, private jwtHelper: JwtHelperService){} canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { const token = localStorage.getItem("jwt"); if (token && !this.jwtHelper.isTokenExpired(token)){ return true; } this.router.navigate(["login"]); return false; } }
Inside the canActivate
method, we check if the token expired. To check the validity of a token, we use the JwtHelper
service. The JwtHelper
service is defined in the @auth0-angular-jwt
library which is a lightweight library that provides some helper services to easily work with JSON web tokens in Angular. If a token is valid, our guard returns true. Otherwise, it navigates the user to the home component and returns false.
After the guard implementation, we are going to apply the AuthGuard
service to the CustomersComponent
route in the app-routing.module
. To apply the AuthGuard
, we simply provide the service name in the CustomersComponent
‘s route object by using thecanActivate
attribute:
const routes: Routes = [ { path: '', component: HomeComponent }, { path: 'login', component: LoginComponent }, { path: 'customers', component: CustomersComponent, canActivate: [AuthGuard] } ];
The canActivate
property in the Route
object is an array. That means we can specify more than one service. At this point, if we are not authenticated and try to visit the Customer
page, we will be redirected to the Login
page.
Before we continue, let’s add a few changes to the home.component.ts
file:
constructor(private jwtHelper: JwtHelperService) { } ngOnInit(): void { } isUserAuthenticated = (): boolean => { const token = localStorage.getItem("jwt"); if (token && !this.jwtHelper.isTokenExpired(token)){ return true; } return false; }
Accessing Protected Resources
To access the protected resources we need to send the JWT token in the Authorization header with each request. The server is going to verify the token and grant access to protected resources.
In our CustomerComponent
, on the component initialization, we are going to send a request to the server to access a list of customers.
import { Component, OnInit } from '@angular/core'; import { HttpClient, HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'app-customers', templateUrl: './customers.component.html', styleUrls: ['./customers.component.css'] }) export class CustomersComponent implements OnInit { customers: any; constructor(private http: HttpClient) { } ngOnInit(): void { this.http.get("https://localhost:5001/api/customers") .subscribe({ next: (result: any) => this.customers = result, error: (err: HttpErrorResponse) => console.log(err) }) } }
Here, we send an HTTP GET request to the http://localhost:5000/api/customers
endpoint with the JSON web token in the Authorization header. Yes, you can’t see the authorization header in the request but it will be there due to the auth-jwt
library configuration:
If the token is invalid the server is going to reply with the 401 Unauthorized
response. If the token is valid, then we are going to see a list of customers.
Now, all we have to do is to show some results in the customer template file:
<h1>Customers</h1> <ul> <li *ngFor="let cust of customers">{{ cust }}</li> </ul>
Role-Based Authorization
Right now, we have a fully functional application (the backend and the frontend part) that uses the JWT features for user authentication. But, because we have only the [Authorize]
attribute on top of the Customers controller’s GET action, all the authenticated users have access to that endpoint.
What if we don’t want this type of behavior? What if we want only Managers to have access to that endpoint?
Well, to accomplish that, we need to make a couple of changes to our Web API part.
First, let’s modify the [Authorize]
attribute to give access only to a user with the Manager role:
[HttpGet, Authorize(Roles = "Manager")] public IEnumerable<string> Get() { return new string[] { "John Doe", "Jane Doe" }; }
Excellent.
Additionally, let’s modify the Login
action in the AuthController
to set up the user claims:
if (user.UserName == "johndoe" && user.Password == "def@123") { var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("superSecretKey@345")); var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256); var claims = new List<Claim> { new Claim(ClaimTypes.Name, user.UserName), new Claim(ClaimTypes.Role, "Manager") }; var tokeOptions = new JwtSecurityToken( issuer: "https://localhost:5001", audience: "https://localhost:5001", claims: claims, expires: DateTime.Now.AddMinutes(5), signingCredentials: signinCredentials ); var tokenString = new JwtSecurityTokenHandler().WriteToken(tokeOptions); return Ok(new AuthenticatedResponse { Token = tokenString }); }
In the changed parts of the code, we create claims by adding the username and the role claim to the Claim list. Now, our “johndoe” user is a Manager and it should have access to the Customer’s GET action. These claims are going to be included in our token. If we try to log in with the Angular application, everything should work as before without any problems.
Finally, let’s check what is going to happen if the “johndoe” has the Operator role and not the Manager role. To simulate this, we need to modify the role claim from the Manager to the Operator:
var claims = new List<Claim> { new Claim(ClaimTypes.Name, user.UserName), new Claim(ClaimTypes.Role, "Operator") };
Now, we still are able to log in but once we try to access the Customer’s GET action, we are going to get the 403 Forbidden
response:
Awesome, our authorization part works like a charm.
JwtHelper DecodeToken
One more thing though. Let’s see how we can extract the data from the token on the client side.
The jwtHelper
service has the decodeToken
function which can decode our token into the JSON object. Because we have already injected the JwtHelper service into the AuthGuard
service, let’s modify that service a bit just to see how the decodeToken
function works. We are going to add one line of code that checks if the token exists and if it hasn’t expired:
if (token && !this.jwtHelper.isTokenExpired(token)){ console.log(this.jwtHelper.decodeToken(token)) return true; }
Once we log in again, we can see the result in the console window:
aud: "https://localhost:5001" exp: 1650718465 http://schemas.microsoft.com/ws/2008/06/identity/claims/role: "Manager" http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: "johndoe" iss: "https://localhost:5001"
Conclusion
By reading this post you have learned:
- How to configure cross-origin requests in the browser and on the server
- To login users in AngularStore save JWT in local storage.
- How to remove JWT from local storage and how to log out a user in Angular
- To protect Angular routes with the
CanActivate
interface - How to access protected resources on the server by sending tokens in the Authorization header
In the next article, we are going to learn about Refreshing Tokens in Web Applications.
Great Article, can you please explain how to decode JWT token on server side. meaning how to get user details from JWT token received with the request
Once you are inside the authorized action, you can use the User property to extract all the claims. For example:
[Authorize]
public IActionResult Privacy()
{
var claims = User.Claims
.Select(c => new { c.Type, c.Value })
.ToList();
return Ok(claims);
}
how do you implement logout in .net ?
assuming i dont want angular or any front in my project ?
Hi Marinko,
I have a few problems trying to get this to work. A couple of things that threw me in the page: Under ‘Installing Angular Jwt Library’ you have “To install the angular2-jwt library, …”. I had a look at the npm pages which seem to indicate ang2-jwt is for angular2+ and ang-jwt is for AngularJS, so I tried to install angular2-jwt. Once I fixed that, I found ‘whitelistedDomains’ and ‘blacklistedRoutes’ in the config don’t work and are now ‘allowedDomains’ and ‘disallowedRoutes’ respectively.
However, correcting these still leaves me unable to access customer data. Adding the [Authorize] annotation to the route in the web API project results in the server always returning 401. If I leave the annotation out but still have the guard in the client, it seems to work properly: I can access customers, but only after logging in. I checked the request header and the token is included, but checking the token on jwt.io resulted in ‘Invalid Signature’. until I put something (anything) in the ‘your-256-bit-secret’ box Did I miss something? Everything works perfectly – as long as I don’t add that [Authorize] annotation. Have you any ideas where I might have gone wrong?
The angular2-jwt was left from the old version of the article, but you have a good command to install a valid version:
As stated on the official npm page: https://www.npmjs.com/package/@auth0/angular-jwt version 4 is for Angular v9 and for v10 you need to use version 5.
Regarding other issues, please download our source code and compare your solution with it. This is the easiest way to find differences that may cause you problems.
… stupid, stupid, stupid.
My problem was a Security Key typo in Startup.cs. It didn’t seem to cause me any problems in tutorial part 1, so I didn’t notice it.
Curious. It’s in the respective github repos (under ‘About’) where angular-jwt identifies as for ‘AngularJS’ (and ang2-jwt for ‘Angular2+’)
Feel free to delete this exchange.. 🙂
No need to remove our discussion. Maybe someone else will have a similar problem and your solution may provide some sort of hint. Every comment is a good comment unless it is comment of hate 🙂
Hi Marinko,
Is it possible to show us how to validate with Azure AD users?
To be honest, I didn’t work with Azure AD users, but everything can be researched and learned for sure 🙂
Well, it is invalid because the signature is wrong. Comoare your siurce code with ours. Also verivy that the claims are correct.
I missed adding Authorize attribute on top of Every Request Method example [HttpGet, Authorize]
I thought just by putting [Authorize] on top of the controller is enough.
Thank you for sharing your code and techniques. Your tutorials helped me a lot!!!
Hi! I always get this answer after a successful login from the asp.net when I try to call a method: http://localhost:5000/Account/Login?ReturnUrl=%2Fapi%2FClient%2Fdetails Why? The token is valid. It contains an authorized Role and it didn’t expire.
Angular:
getAllWithContactDetails(): Observable {
return this.http.get(`${links.API_URI}/api/Client/details`, {
headers: new HttpHeaders({
'Accept': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('token')}`
})
});
}
I am not sure I understand the question. What response do you get when you try accessing the protected action in your controller? You can attach a picture for a better clarification. You can share the Angular code as well as the API action’s code.
Hi Marinko,
Using .NET Framework, I used to commonly use code like:
string strCurrentUserId = User.Identity.GetUserId();
in my WEP API controllers to get the current logged on user. This has changed in .NET Core 31. as far as I can tell but none of the code I find seems to work. I just keep getting a null value. Do you have any suggestions? Much appreciated.
For clarity, here is my test code for logging in:
[HttpPost]
[Route("login")]
public async Task Login(Login login)
{
if (ModelState.IsValid)
{
try
{
AppUser appUser = await _userManager.FindByEmailAsync(login.Email);
if (appUser != null)
{
await _signInManager.SignOutAsync();
Microsoft.AspNetCore.Identity.SignInResult result = await _signInManager.PasswordSignInAsync(appUser, login.Password, false, true);
if (result.Succeeded)
{
var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("superSecretKey@345"));
var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);
var tokeOptions = new JwtSecurityToken(
issuer: "http://localhost:5000",
audience: "http://localhost:5000",
claims: new List(),
expires: DateTime.Now.AddMinutes(5),
signingCredentials: signinCredentials
);
var tokenString = new JwtSecurityTokenHandler().WriteToken(tokeOptions);
return Ok(new { Token = tokenString });
}
}
ModelState.AddModelError(nameof(login.Email), "Login Failed: Invalid Email or password");
}
catch (Exception exc)
{
var msg = exc.Message;
}
}
return Ok();
}
Hi. After you send an access token to the protected action inside the controller, you can get any claim by using the Claims list:
var claims = User.Claims
.Select(c => new { c.Type, c.Value })
.ToList();
I hope this will help.
Thanks again for your prompt reply.
Using your provided code, I just get 3 claims: “iss”, “aud” and “exp”. Am I supposed to be able to add other claims such as user id and email? I’m really looking for the user id.
Of course you can. In the same way we add roles in the login action. So as soon as you login your user, you can take the id and place it in the list of claims.
Hi Marinko,
Great article and superb work.
I was wondering if it is possible to use decodeToken to hide and show components in a sidenavbar after login based on the role in token returning. At the moment the token is returning with the roles “user” or “admin” based on the user permissions but I cant figure out how to use this to hide and show components.
Thanks!
Hello Mike. Thanks a lot for reading this article and for the kind words.
Of course, you can use the decoded token to hide some components in the menu bar. Basically, as soon as you log in and retreive the token, you can decode it and extract the role claim to the public property inside the auth service (or wherever you have your auth logic). Then in the menu component you should conditionaly render your links based on the value of that role property you just extracted. Of course this is easire solution but it can get even better by using Subject and Observable. For example, you can create the mentioned objects:
private _authChangeSub = new Subject()
public authChanged = this._authChangeSub.asObservable();
and as soon as the login is successfull, you can emit an event to all the subscribed components:
this._authChangeSub.next(role);
and then in the menu component:
ngOnInit(): void {
this._authService.authChanged
.subscribe(res => {
this.role = res;
})
}
And now in the html part you can conditionaly render your links.
I hope this could help you.
Mariko,
I have another question. I’ve created new application .net core 3.0 Angular 8 template and I added windows authentication manualy and now I want to add roles. Will your method described in this post will work with Windows authentication?
Thanks!
Hi Marinko,
First of all great article, helped me a lot. However, I have a question.
In one solution I will have an application without Angular (MVC only) which will have Windows Authentication and few applications with Angular and I would like them to use Windows authorization from first application.
Should I use only JWT and CORS to do this?
Would every application have to have a Windows authorization or is it enough to have it in one?
Do you have any advice?
Thanks!
Hello Xia. If you are going to have multiple client application and you want to have a single authorization server, then you should use the IdentityServer4 as your IDP (identity server provider). With it you can provide the authorization actions for all of your client applications. On this link https://code-maze.com/identityserver-4-series/ you can learn a lot about the IdentityServer4. Also we have a security book with the ASP.NET Core Identity user management actions implemented, so you might want to check that out as well. We didn’t cover the windows authentication in articles nor the book, but once you learn aboud IS4, the rest is easy.
Thank you so much!
I was just looking for a book on a similar topic as my knowledge of authorization is very little. I’ll take a look 🙂 Thanks!
I did take this error : Unexpected token e in JSON at position 0 at JSON.parse can you help
As much as I would like to help, I really have no idea why you have that error because I have no other information from you. My suggestion is to take a look at our source code and compare to yours. If you can’t find the error, you can post the source code and a better description and I will see if I can help you with that.
Hi,
I have got this working perfectly locally using IIS Express in Visual Studio 2019.
However when I deploy to an actual IIS On my machine or to another server the Bearer does not seem to be sent with any requests after login and thus everything I get back is 401.
The bearer is being set up correctly and I can decode an look at it from the login page.
Any ideas what to check on this?
Well this JWT configuration should add token to the HTTP request (every single one). But all I can think of is that you didn’t whitelist a new URI for deployed server. If you still have localhost:5000 than, you have to add additional one because your deployed server app is not served on localhost anymore.
Great Article, Thanks !
Thank you. We have started the ASP.NET Core Identity series: https://code-maze.com/asp-net-core-identity-series/. So feel free to check it out.
Great write up! Is it safe for me to assume that a lot of the .NET code written here could easily still apply to .NET 4.6.2, MVC 5?
Hello Will, thank you for reading our articles. I must say that I believe that the code could be reused, but I also must say that I didn’t apply it to .NET or MVC, so can’t be 100% sure. But if you find time, and test this, you can inform us about your results. One more time, thanks a lot.
Hi Marinko,
As usually, great job, well organised.
About the issue of Vasily, I have the same issue when using the new version @auth0/angular-jwt
I have fixed by importing into AppModule as follows:
JwtModule.forRoot({
config: {
tokenGetter: tokenGetter,
whitelistedDomains: [“example.com”],
blacklistedRoutes: [“example.com/examplebadroute/”]
}
and don’t forget to implement the following function
export function tokenGetter() {
return localStorage.getItem(“jwt”);
Then other components, we need import
import { JwtHelperService } from ‘@auth0/angular-jwt’;
and use JwtHelperService without instanitate JwtHelperService.
Thanks again for constribution
Regards,
Tam
Thank you Tam, and yes you are right this is something that needs to be done with the new angular-jwt library. As you can see in the article (where I mention that if people use Angular version 6+ they have to use a new library) I have left the link towards the official documentation. I appreciate a lot your contribution, that is really awesome.
Hello Marinko.
Now again with your tutorial, found new problem.
When trying login, receive this:
core.js:7187 ERROR Error: Uncaught (in promise): NullInjectorError: StaticInjectorError(AppModule)[JwtHelperService -> InjectionToken JWT_OPTIONS]:
StaticInjectorError(Platform: core)[JwtHelperService -> InjectionToken JWT_OPTIONS]:
NullInjectorError: No provider for InjectionToken JWT_OPTIONS!
NullInjectorError: StaticInjectorError(AppModule)[JwtHelperService -> InjectionToken JWT_OPTIONS]:
StaticInjectorError(Platform: core)[JwtHelperService -> InjectionToken JWT_OPTIONS]:
NullInjectorError: No provider for InjectionToken JWT_OPTIONS!
at NullInjector.get (core.js:1354)
at resolveToken (core.js:1681)
at tryResolveToken (core.js:1607)
at StaticInjector.get (core.js:1470)
at resolveToken (core.js:1681)
at tryResolveToken (core.js:1607)
at StaticInjector.get (core.js:1470)
at resolveNgModuleDep (core.js:23118)
at _createClass (core.js:23186)
at _createProviderInstance (core.js:23151)
at resolvePromise (zone-evergreen.js:797)
at resolvePromise (zone-evergreen.js:754)
at zone-evergreen.js:858
at ZoneDelegate.invokeTask (zone-evergreen.js:391)
at Object.onInvokeTask (core.js:30885)
at ZoneDelegate.invokeTask (zone-evergreen.js:390)
at Zone.runTask (zone-evergreen.js:168)
at drainMicroTaskQueue (zone-evergreen.js:559)
at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:469)
at invokeTask (zone-evergreen.js:1603)
I’ve been searching a bit on the internet and usually if people face this error, they have installed wrong library. So if you are using our Angular project, which is version 4, then you should install angular2-jwt. But if you are having an angular project with a higher version then you should install @auth0/angular-jwt.
Angular CLI: 8.0.6
Node: 10.16.0
OS: win32 x64
Angular: 8.0.3
… animations, common, compiler, compiler-cli, core, forms
… language-service, platform-browser, platform-browser-dynamic
… router
@auth0/[email protected]
This code works (auth-guard.service.ts)
====================================
import { JwtHelperService } from ‘@auth0/angular-jwt’;
import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from ‘@angular/router’;
import {Observable} from ‘rxjs’;
export class AuthGuard implements CanActivate {
constructor(private router: Router) {
}
private jwtHelper: JwtHelperService = new JwtHelperService();
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | boolean {
var token = localStorage.getItem(‘jwt’);
if (token && !this.jwtHelper.isTokenExpired(token)) {
console.log(this.jwtHelper.decodeToken(token));
return true;
}
this.router.navigate([‘/’]);
return false;
}
}
Great Vaisly. Just one thing, I believe that you don’t have to instanitate JwtHelperService but you can use it in the constructor as we did with the JwtHelper (just replace JwtHelper with JwtHelperService). Afterall it is a service so why instanitating it, when we can use dependency injection and inject it inside the constructor method. Thank you for your code.
I see, but that’s the thing, using it in the constructor generate an error.
I don’t understand that
It is strange, in the official documentation writes differently (look all the way down and you will see injected service) https://www.npmjs.com/package/@auth0/angular-jwt.
Now I am reading this documentation and probably you need to register JwtModule in the main module and to use some configuration as described in documentation.
But again, thanks for the code, it can help our readers for sure.
thanks to you
It was found that an error occurs when navigating to page with authentication check. When navigate to other pages, the error does not occur
Thank you, a very useful article, especially for a beginner like me. After 2 days I was able to run your example, however, all I got from localhost:4200 is a completely blank page with the correct title.Tell me, please, what should I do next
Hello Vasily. Well, the first thing you can do is to download our source code (for finished projects) and to compare your solution with ours. If that doesn’t help, you can post your solution on github and let us know. Then we can check it (but this will take more time, due to lack of a free time from our side).
Hello, Marinko. Thank you for your prompt reply. I will check my code and compare it with your sources, it will be useful for me. If not will turn out – will do as you suggested. Thank you for help and for your articles.
Thanks for this article – found it really helpful. Would also like to see some implementation using IdentityServer, if possible, which also supports auth via OpenID. Thanks again.
Thank you for reading this article. We are glad that you found useful information in it. Thank you for the suggestion as well. All the best.
A little consideration: for Angular 6+ Applications you need to use @auth0/angular-jwt instead of angular2-jwt. Hope it helps!
That is exactly why we created a starting project. You can never be sure with libraries and their versions 🙂 Thanks for your info, it means a lot. We are going to update this article. All the best.
Oh cool! I was following your example while buiding an Angular7 App and I found this little thing. This article helped me a lot!
I am so glad to hear that. And it is aa grea of you to sharing your knowledge with us. Thank you for that.
hi…
how to create code for logout in server side (.net core side) ?
Hello. Well I wouldn’t recommend that, because all you have to do is to remove your current token from a storage (whatever the storage is) and you are done. But if you want to do it on server side, you would probably have to mess with the token somehow and to return that token back to the user. But it seems like a complication to me.
Hello @disqus_GtEeIZUUDN:disqus
What is the best way to implement e-mail verification in .net core & Angular?
Here is a package which
– Makes integrating JWT Bearer Token Security in your Asp Net Core 2.0+ app a breeze!
– Facebook auth integration.
– Also, Swagger UI integration!
It is called AspNetCore.Security.Jwt
GitHub: https://github.com/VeritasSoftware/AspNetCore.Security.Jwt
Thanks for mentioning.
In Chrome this works like a chatm but in Firefox I geht this error :Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/API/Auth/login (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
Why do it works in Chrome but not in Firefox etc.?
Hello Ray. I am not really sure about that. We have tested it with Chrome. I have seen some answers in which they say that there is problem with old Firefox version and that it should be updated, have you tried that? Other than that, I am not quite sure why this happens, especially because we have enabled cors for any origin and any header.
Thank you for the articles. I have a working application, however logging in following the customers route simply returns it to HomeComponent. The code responsible is this.router.navigate([“/”]); in LoginComponent. It returns customers data if changed to this.router.navigate([“/customers”]);
Is there a solution to this that returns the login result to the calling component, in this case CustomerComponent?
Hello Mark, thank you for reading these articles. You can use the Router in some kind of service to take your previous route and to just inject that service into the login component. Than you can check if there is previous route and navigate to it or to just navigate to the home. Or you can use a custom service to preserve the route you have come from and then just to inject that service and to navigate either to that cached route or to the home…. I believe there are other ways too, but those just came out of my mind right now.
I hope this helps. All the best.
Hi, thank you very much for the articles. I’ve had pretty much the same setup and they helped me to clean it up.
I’m trying to add social login (Facebook, Twitter…) using the ASP.NET Core Identity but I’m not able to make it work with my Angular app.
I’d love to know if it’s even possible because all documentation I read was using the built-in MVC of ASP.NET Core.
If it’s possible I think it might make a nice article.
Thank you for this article. I’ve got one more question: How can I read the value of the http://schemas.microsoft.com/ws/2008/06/identity/claims/role claim in Angular?
Thank you!
Hello Julida. Thank you for reading this article. The decoded token is nothing more than a JSON object with key value pairs. So to extract value from any JSON object, you use the following syntax: nameOfJSONObject[key]. So for example if you have something like this in Angular:
let obj = this.jwtHelper.decodeToken(token);
You can extract the role with this syntax:
let role = obj[http://schemas.microsoft.com/ws/2008/06/identity/claims/role];
or the exp:
let exp = obj[exp];
All the best.
Thank you for this great article, and the previous one. I’ve spent the weekend going them slowly and methodically and I’ve learnt a stack load. Thanks so much!
I’m just wondering now, what is the appropriate way to refresh the token?
So if i set the expiry to 5 min, and the user is active on my site, I wouldn’t really want him to have to log back in every 5 minutes.
What is the best pattern to implement this?
I guess I could implement a method in my auth service called renewToken or similar and call this behind the scenes somehow?
Would this be a good pattern?
Hello Bruce. Thank you very much for reading our articles and even more for your kind words.
Your solution for refresh token logic is very good. In one of my projects, I did something like this:
In auth servise, I have set one property shouldRefreshToken. Every action in my project (that should refresh a token would set this prop to true). I have also implemented one interval to check that prop in every 60 seconds. If prop value was true I would send a request to refresh a token. Of course you need to check if a token is expired prior to refreshing it, otherwise, there is no sense in refreshing it.
To this day, this solution works like a charm.
Hope this helps.
Thank you one more time and all the best.
Aha, great. Thank you!
JWT must have 3 parts error help me please))) https://uploads.disquscdn.com/images/dfe14e1c4934b69d8a3f1c9c2de93be8454bfa7bb734983908298cb265bc3c4c.png
Hello Daemon. First of all thank you so much for reading our articles. I am sorry to see that you have a problem but let me try to help you. Your error states obvious: Your token must have 3 parts (Payload, Header and Signature). This is something that you provide on your server side. So your problem probably exists in the .NET Core part of this tutorial.
My recommendation is to check your code form the part 1 of this tutorial. You can even place a break point in the Login action in AuthControler to check out what is your token result. The tokenOptions variable must have all the three mentioned parts in it (among many other properties).
If you can’t find error, I advise you to upload your code and we will look at it and try to help you.
All the best.
I’m solved this problem, but i have a new issue))) https://uploads.disquscdn.com/images/c64a637104e34fc6ed88e34cbd0dc3b1faaf600e464fb31875f5ce428efeeb21.png
I am sorry, but I have no idea what this is. I have found something like this maybe it can help you: https://stackoverflow.com/questions/45195278/aspnetcore-with-angular-error-nodeinvocationexception-the-node-invocation-timed
My Customers Controller)))
using System.Collections.Generic;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace AspCoreServer.Controllers
{
//http://34.65.74.140/authentication-aspnetcore-jwt-1/
[Route(“api/[controller]”)]
public class CustomersController : Controller
{
[HttpGet,Authorize(Roles = “Operator”)]
public IEnumerable Get()
{
return new string[] { “John Doe”, “Jane Doe” };
}
}
}
https://uploads.disquscdn.com/images/930150a408d2d370c4acf2dd0345a2e693da8af9d7b6fb4f1aadacc526c982fd.png
Ty ))) I solved my problem. I forgot to rewrite the authguard …)))
my main task is to integrate authorization with social systems …