Little Known Angular XSRF Protection Support In Http & HttpClient APIs (v2.0+ vs 4.3+)

This post is about a new feature / code restructure in Angular v4.3+ that is pretty well documented, yet, hardly talked about in posts, and worth drawing special attention to.

The feature we are talking about here is Angular helpers for guarding against XSRF attacks in its old and new HTTP modules.

What Is XSRF? (Cross Site Request Forgery)

XSRF (Also knwon as CSRF) is a form of web security attack that can allow others to impersonate your identify and perform some actions on websites that you are already logged in to. Let’s start with an over simplified version of how the attack and protection work (as I understand them).

XSRF Attack

  • You login to website A and get a session cookie, maybe use it a bit
  • You open website B in a new tab or even the same tab, you are still logged into website A
  • The owner of website B (or someone who hacked it) happens to be a user of website A too, and knows what calls it sends to the server to perform different tasks
  • Website B loads a hidden form with the submit URL going to website A
    . It could be sending an email on your behalf, deleting many important items, whatever that is you can perform in website A
  • Website A takes the request and performs it, because you are still logged in

XSRF Protection

There are many ways to protect against this attack. Mainly you’d use server-generated token stored in somewhere that’s not a cookie.

A classic server side application with a single form each page that submits back to the server can generate a token as a hidden field in the form, and then validate it on submit, and generate a new token for the next page etc. Website B will not have a way to generate a valid token when trying to simulate the server form.

A client side application (SPA) could do the same with headers, sending the token in a header when making any API request (A.K.A AJAX call), and getting the new token in the response of that API / AJAX call.

The initial token may be obtained via a call to a known API, or in a cookie that’s downloaded when the HTML page is loaded. Since the other site can only do only put a form on its own page, it cannot modify headers to inject the token, or call the API directly due to CORS (Cross Original Resource Sharing) policy.

Angular HTTP APIs & XSRF Protection

By default the Angular v2+ Http service (from angular/http HttpModule) had builtin support for the Cookies To Headers XSRF protection technique we just mentioned.
If it detects a cookie with the name XSRF-TOKEN, it adds an HTTP header named X-XSRF-TOKEN with the same value to the next HTTP request you make.

Since the support is so transparent, I have seen developers who did not even realise it’s there. If you are a front end developer who had someone else on the backend implement the server issuing and validation of the tokens, you may not even realise it’s there.

But things changed slightly in Angular v4.3, that you probably need to be aware of.

HttpClient

In Angular v4.3, a new library for creating HTTP (AJAX) requests was added to Angular.

Instead of injecting an Http object from @angular/http as you did since v2.0, you inject an HttpClient from @angular/common/http. The new HttpClient has several new features but most notably:

  • Automatically maps responses to JSON by default (configurable)
  • Added a pipeline for injecting middleware to requests/responses (called interceptors, like those of AngularJS v1.x)
  • Has some really cool testing utilities that are much simpler than the old v2.0 Http module

Whether you like it or not, you’ll probably end up using the new HttpClient in your Angular applications. This is because starting Angular v5.0, the old Http will be deprecated (so it may be removed entirely in v6).

For the record, the relatively quiet introduction of the new module in v4.3 and the deprecation of the old in v5 still makes me feel anxious regardless of how good the new one is. The old one generally just worked, and the way it’s replaced reminds me of the 3 router versions that were written during Angular v2.0 pre-releases.

XSRF Interceptors

Since the new HttpClient came with proper support for request and response interceptors, it made total sense for the XSRF support in it to be implemented as interceptors as wel, not as part of HttpClient itself.

This is all cool and good design, but there is a catch, which although is well documented, it’s not having enough people talking about on Medium and Twitter etc.

The XSRF in HttpClient is an opt-in feature. It’s NOT enabled by default, unlike the Http service. This means that you could easily migrate your code from Http to HttpClient and not realise that your builtin XSRF support has been lost, until you test the application and you start getting 403 Unauthorized errors from your API of course.

Luckily, all you need to do to get the support back is just import another module, like:

// import { HttpModule } from '@angular/http';
import {
  HttpClientModule, HttpClientXsrfModule
} from '@angular/common/http';
// ...

@NgModule({
  declarations: [
    AppComponent,
    // ...
  ],
  imports: [
    // Now this one is gone:
    // HttpModule,

    // New replacement
    HttpClientModule,
    // Restore Xsrf support
    HttpClientXsrfModule,
    // ...
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Gotcha

The old HttpModule supported sending the XSRF-TOKEN header for all HTTP requests. While the new HttpClientXsrfModule made sure it doesn’t send the header for GET or HEAD requests.

GET requests don’t make much sense for XSRF attacks anyway because the attack is about changing data while impersonating you (the attacker cannot get the result anyway because of CORS rules). GET requests by definition should not change data.

However, if your API relies on this, your app might break when you move to HttpClient. In that case you might want to look at this Github issue I created and apply the workaround github.com/angular/angular/issues/19885

More Goodies

The HttpClientXsrfModule also makes it easy to change the cookie & HTTP header keys separately if you require that.

Of course you have to remember that both XSRF protection and JSONP require server support as well from the API server you are calling for them to function.

Finally, the same support is also included as opt-in for JSONP requests as well, by adding HttpClientJsonpModule (also from @angular/common/http) to your imports. This utilizes the power of interceptors that allows them to avoid sending an HTTP request completely and do something completely different instead.

As I said, the usage of HttpClient in general, as well XSRF support (and what is XSRF in general) is well documented by the Angular team.
Check it out at https://angular.io/guide/http.
I still noticed that not enough people are talking about this feature and the actual change, so, hopefully this post can bring some awareness to it.

My Experience Running Jest In A Real Angular CLI Project On Windows

Jest is an alternative test runner by Facebook. It’s popular in React world. I was wondering how it’ll be like in an Angular CLI app. I knew a new semi-empty app won’t be a good enough test, so, I checked it in a real private project I’m working on, so see if it has any benefits for the project and the team.

While I cannot share the project codes, I can still share how the experiment went, as I talked about it yesterday at the ng-sydney Angular usergroup April gathering, also, as I logged it in a related Angular CLI github issue by a friend ng-sydney attendee.

Introduction

For the record, I tried Jest with instructions from @thymikee‘s post (which uses jest-preset-angular), and it worked just fine.

Let me share my findings:

Result Summary

  • It works!
  • It took some small changes.
  • It seemed slower in my case.
  • It caught more errors than Webpack/Karma/Jasmine, which I was very grateful for.
  • The experience is quite different though that I won’t make it the default my team yet.

Required Changes

  • I started with all the steps in the post above.

  • For some libraries I had to follow this github guidance, which made the jest property in my package.json look like:

    The transformIgnorePatterns is the most interesting here. I used \\ because I’m on Windows, and I used ^<rootDir>\\ to try to speed things, although it didn’t make a big difference. There’s also "allowJs": true in "compilerOptions" in src/tsconfig.spec.json.

  • I also had to change the tests. The post mentions all the changes needed (mostly only changing jasmine. to expect. in a few places).

    But there’s another change I had to do, which is removing any expectationFailOutput, which is when you give a custom error message for when a matcher fails to match. Seems Jest does not support that.

Gains

  • Jest seems to run tests in more isolation than the current Webpack/Karma/Jasmine combo, which showed me some errors in my tests that somehow didn’t show before.

  • Jest is reporting which tests are taking too long, the slowness warnings were useful smells to identify not-greatly-written tests.

  • The watch mode is very nice, even though it seems to work off git changes not file watching, which can be confusing at first when you see slightly more files than expected, but it’s still very useful.

Issues

  • As mentioned in Required Changes above, now I cannot use custom error messages in my test matchers (that said, it’s true that default matcher errors are very beautiful and obvious, but still).

  • At the moment, it seems the jest-preset-angular initialization code needs optimization. It doesn’t call polyfills.ts and instead calls its own set, even though it’s optimized for Angular CLI (for example, it uses src/tsconfig.spec.json).

    More importantly, it imports the entire rxjs library, which might hide errors when you forget to import some operators.

  • It’s surprisingly slower than the Webpack/Karma/Jasmine combo!

    For my 196 tests, the Angular CLI v1.0.0 default test runner (with Angular 4) takes ~ 55 seconds, while Jest takes ~100 seconds.

    Update: That conclusion might not be accurate. The time I quoted for each test runner is what the test runner reported. This might for example not include Webpack compilation and browser opening in Karma and might be total time in Jest. If so, then the total time would be the same.
    Thanks @hugoccampos for bringing this to my attention.

  • No browser tests debugging apparently (It might be my ignorance here). A bit harder maybe for those starting testing.

    The Angular CLI does a great job at making testing easy for those not used to it.

  • When Jest itself fails to run, for example if I put a badly formatted regex for transformIgnorePatterns shown above, or mess up something in my src/tsconfig.spec.json file, the errors it shows are very cryptic and tell you nothing that can lead to the real issue (unlike matching errors in tests, which are very nice).

Angular 4.0 Final Is … Here! And Angular CLI 1.0 Is Final Too!!

Update (March 24)

Angular 4 Final Is Out Already

Check out the official announcement, and github changelog.
After that, check the updated documentation for Angular 4 at angular.io.
If you need access to Angular 2 docs, check the black-and-white official docs archive at v2.angular.io.

Update 2

And, on the same day, just as mentioned earlier in the post below…

Angular CLI 1.0 Final IS Out Too

Checkout the changelog, README / Docs.
And if you ever used Angular CLI before v1.0 final, check the official upgrade guide.

Hello, This is Meligy from GuruStop.NET.
Good news, we are expecting Angular 4 final any hour now!

How Do We Know?

During the ng-sydney Angular meetup gathering last Wednesday, Stephen Fluin from the Angular team repeated a couple of times that Angular 4 final is expected this week.

A quick look into the latest Angular team meeting notes also confirms that Angular 4 is due on Thursday, March 22 (although they mentioned there are a couple blocking issues, so, it might be on Friday or so).

Angular CLI, the best tool to create, develop, and test Angular applications, is also going to be released as 1.0.0 final alongside Angular 4.

P.S.
If you prefer to add server-side rendering, you might check Angular Universal fork of the CLI fork for Node, and `dotnet new Angular` for ASP .NET Core. If you need to build an Ionic app, check Ionic CLI 3 beta. They all would come with Angular 2 support by default only though, while the official Angular CLI supports generating Angular 4 projects by running `ng new app-name –ng4`.

[Video] Angular 4 And The Angular CLI

If you want to learn more about Angular 4 and the Angular CLI, see Stephen Fluin`s video here:

[Video Playlist] More Recent Talks, NG-NL

If you are interested in more free up-to-date Angular videos, the NG-NL Angular Netherlands conference also took place last week, and many session videos are available now in this YouTube playlist:

https://www.youtube.com/playlist?list=PLQi8NNYCH8TDFnOhjrIsjZGMD6Ks8SQid

Angular 4? (Not 3!!)

Just for those who don’t know, the reason there is no Angular 3 is that the Angular router for Angular 2 has been rewritten 3 times, and the NPM package for Angular router is now 3.x, while all other Angular packages are 2.x.

To make all the packages the same version again, the Angular team skipped version 3 entirely, and jumped directly to version 4.

It’s worth reminding though that Angular 4 is mostly backwards compatible with Angular 2. You should expect most if not all your applications to continue to work with it.

And a final reminder, it’s “Angular”, for Angular 2+, and “AngularJS” for Angular 1.x. These are the names that the Angular team prefers, and that’s what you’ll see me use more often going forward.

What’s Next?

Once Angular 4 final is out, I’ll send you a follow up email, with a very customized writeup of what I personally find most exciting about Angular 4, and can’t wait to use in all my production projects.

I’ll also share some awesome resources for RxJS and TypeScript.

Stay tuned!

Cheers,

– –

Meligy

ng-sydney | Usergroup Founder & Organizer

Shared Modules In Angular Apps: Providers Best Practices And What Does `forRoot()` Do?

When you write a shared module for your application, that contains stuff you use in other modules in the same app, you typically want all the services in that module shared only once.

If you just put the services in the providers property of the shared module’s NgModule() decorators, you might get weird cases, especially with lazy loading, when it feels like there’s more than one instance of the service. This is bad if you want to have shared state.

So, there is a better way to write your shared modules:

import {NgModule, ModuleWithProviders} from '@angular/core';
import {CommonModule} from '@angular/common';
// ... other imports

export const providers = [
    // ... your shared services here
];

@NgModule({
    declarations: [...],
    imports: [
        CommonModule, 
        SomeLibraryModule,
        ...],
    exports: [
        SomeLibraryModule.forRoot()
        ...
    ]
})
export class SharedModule {
    static forRoot() : ModuleWithProviders {
        return {
            ngModule: SharedModule,
            providers: [...providers]
        };
    }
}

The forRoot() pattern / convention is very common in libraries, and you’ll see it in things like ng-bootstrap and others. The name isn’t special for the compiler / framework, but it’s a common pattern.

When using these, in the imports section you can just import the module itself (which gives you any declarations needed like directives etc), and in the exports use the forRoot() version of the module so that it’s available for consumers of your shared module.

Then in your other application modules you can add SharedModule to their NgModule‘s imports normally, except for the AppModule.

The AppModule will be the only place where you add SharedModule.forRoot(), like:

Then in your AppModule, import it as:

@NgModule({
    declarations: [...],
    imports: [BrowserModule, SharedModule.forRoot(), ...],
    ...
})
export class AppModule {

}

There is one exception to this though. Your tests.

If you are writing any unit tests where you are importing the SharedModule, you will probably need to import the module with its providers, because there is no AppModule in the test.

Something like:

TestBed.configureTestingModule({
    imports: [ SharedModule.forRoot(), ... ]
})
...

If you haven’t already, have a look at the NgModule official documentation. There’s a main guide, and an FAQ page.

And of course let me know if you have any questions / problems.

Successfully Upgrade Your angular-cli App (Beta 28 & Below) To The Latest @angular/cli Beta


Have you had issues moving from angular-cli beta 28.3 or earlier to the newer versions of the CLI?

Try these steps then!

Global Dependency

This one is as easy as:

npm rm -g angular-cli @angular/cli
npm cache clear
npm i -g @angular/cli

Specific Project

Note: You do NOT need to have the CLI installed globally for this (although it’s a good idea).

First, ensure you have an npm script in your package.json file that looks like:

"scripts": {
    "ng": "ng"
    // ....
}

In this tutorial I’ll replace ng calls with npm run ng -- (note final space ) for those people who may not be able to upgrade their global package.

Now, let’s get to real work.

Commit everything you have in git, then:

npm rm angular-cli @angular/cli
npm cache clear
rm -rf node_modules
npm i -D @angular/cli
npm run ng -- update

Accept all files from update (which used to be called init) other than app module and component, especially (but not limited to) angular-cli.json, polyfills.ts, package.json and main.ts.

Then go to git undo any unwanted change (deleted packages from package.json, missing scripts or files from angular-cli.json, etc). Undo entire app module and component files if you accepted them by accident.

Then

npm install
npm run ng -- build

And you can go roll with npm start / npm run ng -- serve.

All good!