Hey there, fellow Angular enthusiasts! I'm super excited to share my very first post with you all, and I hope you'll enjoy it as much as I enjoyed writing it. Today, we're going to talk about local storage, an essential aspect of web applications, and how to use it in Angular like a pro. We'll also delve a little into some advanced topics like using crypto-js to encrypt and decrypt data. So, let's dive right in, shall we? π
Part 1: What is Local Storage, and why should we care?
Local storage is like a little treasure chest for your web apps, giving them a place to store all kinds of data client-side. Unlike its cousin, session storage, which disappears when you close your browser tab, local storage hangs around for the long haul (or at least until you clear it). It's super handy for storing things like JSON web tokens, user preferences, and app settings. However, it's important to remember that local storage can only store up to 5MB of data per domain.
Now, let's talk about how to work with local storage in Angular. First, I'll show you some plain ol' JavaScript methods to store, retrieve, remove, and clear data. Then, we'll sprinkle some Angular magic on top to create a service wrapper for our local storage API. Ready to learn? Let's do this!
Part 2: Working with Local Storage in Angular
Alright, now that we've got a basic understanding of local storage, let's see how to use it in Angular. First, we'll create a new Angular application using the Angular CLI:
ng new local-app
Once your Angular app is up and running, create a new Angular service with this command:
ng g service local
Our service is going to be a simple wrapper for the local storage API, with methods to add, get, remove, and clear data. Here's what our LocalService looks like:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class LocalService {
constructor() { }
public saveData(key: string, value: string) {
localStorage.setItem(key, value);
}
public getData(key: string) {
return localStorage.getItem(key)
}
public removeData(key: string) {
localStorage.removeItem(key);
}
public clearData() {
localStorage.clear();
}
}
To use our shiny new LocalService in our app, we'll inject it into a component. For this example, let's use the app.component.ts file. Import LocalService, and create an instance of it in the constructor method:
import { Component } from '@angular/core';
import { LocalService } from './local.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private localStore: LocalService) {
}
}
Now that we've got our service set up, let's talk about something a little more advanced: encrypting and decrypting data with crypto-js.
Part 3: Encrypting and Decrypting Data with Crypto-js
Local storage is great and all, but it's not the most secure place to store sensitive data. To add an extra layer of protection, we can use a library called crypto-js to encrypt and decrypt our data before storing and fetching it from local storage.
First, let's install crypto-js in our Angular project using npm:
npm install crypto-js
npm i --save-dev @types/crypto-js
With crypto-js installed, we can import it into our LocalService:
import * as CryptoJS from 'crypto-js';
Now we'll add two new methods to our service to handle encryption and decryption:
private encrypt(txt: string): string {
return CryptoJS.AES.encrypt(txt, this.key).toString();
}
private decrypt(txtToDecrypt: string) {
return CryptoJS.AES.decrypt(txtToDecrypt, this.key).toString(CryptoJS.enc.Utf8);
}
With these methods in place, we can update our saveData and getData methods to use encryption and decryption:
public saveData(key: string, value: string) {
localStorage.setItem(key, this.encrypt(value));
}
public getData(key: string) {
let data = localStorage.getItem(key) || "";
return this.decrypt(data);
}
And here's the complete local.service.ts file:
import { Injectable } from '@angular/core';
import * as CryptoJS from 'crypto-js';
@Injectable({
providedIn: 'root'
})
export class LocalService {
key = "123";
constructor() { }
public saveData(key: string, value: string) {
localStorage.setItem(key, this.encrypt(value));
}
public getData(key: string) {
let data = localStorage.getItem(key) || "";
return this.decrypt(data);
}
public removeData(key: string) {
localStorage.removeItem(key);
}
public clearData() {
localStorage.clear();
}
private encrypt(txt: string): string {
return CryptoJS.AES.encrypt(txt, this.key).toString();
}
private decrypt(txtToDecrypt: string) {
return CryptoJS.AES.decrypt(txtToDecrypt, this.key).toString(CryptoJS.enc.Utf8);
}
}
To test our new encrypted local storage functionality, let's store some data in our app.component.ts file:
import { Component } from '@angular/core';
import { LocalService } from './local.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'local-app';
constructor(private localStore: LocalService) {}
ngOnInit(): void {
this.localStore.saveData('id', 'jk123');
console.log('decrypted data', this.localStore.getData('id'));
}
}
After saving and running the Angular app, you'll see that the data is now encrypted in local storage. Type localStorage in the browser console, and you'll see something like this:
{
"id": "U2FsdGVkX1+xovPDV0m0um6MPlrb+p5aG8Rb09TSWaM="
}
Pretty cool, huh? The data is encrypted, and only our app can decrypt it. When accessing local storage data within the application, you'll get the decrypted data, as shown in the console.log call in the ngOnInit method above.
Remember to always think about security when using local storage, especially when handling sensitive data. Local storage is a powerful tool, but with great power comes great responsibility. Happy coding!
Top comments (8)
Ok, but how do you keep the key secure?
You can keep the key secure by putting it into your environment variables in Angular and then pull it from there.
We're talking about runtime security. Once in the browser, the key is clear.
This IS about runtime security. You store private keys in enviroment.ts, then they are hidden at runtime.
pazel.dev/how-to-keep-your-secrets...
They are not.
They might be stuffed inside the compiled bundle, but they'd still available in plain text inside of it. The environment file is part of the code served to the client.
It usually wouldn't matter for API keys, because they're checked against the web app host, but if we're talking about a cypher key that's not the solution to keep it secret. Not even with code obfuscation.
Yeah, there are plenty of this kinda guides that use symmetrical encryption on frontend technologies but serve no purpose other than making it one step more for malicious actor.
A hybrid system such as openpgp should be used instead. Dynamically generate a key for symmetrical then use it to encrypt the payload. Then, use public key to encrypt the key and private key stays in backend, not in frontend. Https, SSL/TLS typically suffice though.
Thats a good question, there is no advantage to encrypt the data without secure storage of the key.
well thanks for sharin it! will add to my project lab