0% found this document useful (0 votes)
163 views13 pages

Auralia JWT Authentication Guide

The document discusses refactoring an Aurelia application to use JWT authentication. It describes modifying the AsyncHttpClient class to authenticate with a backend service, store the returned JWT in local storage, and send the token in authorization headers for subsequent requests. It also shows updating the DonationService class to rely on AsyncHttpClient for authentication instead of directly calling the backend, and checking local storage for an existing token on app startup to bypass login.

Uploaded by

nguyenvantuyen
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
163 views13 pages

Auralia JWT Authentication Guide

The document discusses refactoring an Aurelia application to use JWT authentication. It describes modifying the AsyncHttpClient class to authenticate with a backend service, store the returned JWT in local storage, and send the token in authorization headers for subsequent requests. It also shows updating the DonationService class to rely on AsyncHttpClient for authentication instead of directly calling the backend, and checking local storage for an existing token on app startup to bypass login.

Uploaded by

nguyenvantuyen
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Jwt in Aurelia

JWT Base Authentication


services

Simple wrapper around aurelia-


http-client

Uses async-http-client for all


API access

+ refactor these classes to


accepts a JWT on successful
authentication

+ … and transmit the token on


every subsequent api access
Refactoring AsyncHttpClient & DonationService

AsyncHttpClient DonationService
• Introduce new • Simplify approach
‘authenticate()’ method into
AsyncHttpClient • No longer retrieve list of
users
• Retrieve JWT from server (if
correct credentials sent) • just invoke ‘authenticate()’
AsyncHttpClient
• Store the token, and send
with each subsequent api • Rely on AsyncHttpClient
request
to generate ‘loggedIn/
loggedOut’ events
• Clear the Token on logout
AsyncHttpClient Constructor

import {inject} from 'aurelia-framework';



import {HttpClient} from 'aurelia-http-client';

import Fixtures from './fixtures';

• Import import {EventAggregator} from 'aurelia-event-aggregator';

import {LoginStatus} from './messages';

LoginStatus 

@inject(HttpClient, Fixtures, EventAggregator)

export default class AsyncHttpClient {

• Inject 

constructor(httpClient, fixtures, ea) {

EventAggregator [Link] = httpClient;

[Link](http => {

[Link]([Link]);

});

[Link] = ea;

}

...
AsyncHttpClient authenticate()
• Post user
credentials to authenticate(url, user) {

donation-service [Link](url, user).then(response => {

const status = [Link];

if ([Link]) {

• If success, recover [Link](configuration => {

[Link]('Authorization',
JWT and store in 'bearer ' + [Link]);

localStorage });

}

[Link](new LoginStatus(status));

• Set Authorization }).catch(error => {

const status = {

header to include success: false,

JWT for message: 'service not available'

};

subsequent api [Link](new LoginStatus(status));

calls });

}

• Publish
LoginStatus event
AsyncHttpClient clearAuthentication()

• Clear the
Authorization
header clearAuthentication() {

[Link](configuration => {

[Link]('Authorization', '');

});

}
DonationService - Constructor

donation-web
donation-client [Link] = {


export default class DonationService {
 auth: false,


 

donations = [];
 handler: function (request, reply) {

methods = [];
 [Link]({}).exec().then(candidates => {

candidates = [];
 reply(candidates);

users = [];
 }).catch(err => {

total = 0;
 reply([Link]('error accessing db'));


 });

constructor(data, ea, ac) {
 },

[Link] = [Link];
 }
[Link] = ea;

[Link] = ac;
 [Link] = {

[Link](); 

// [Link]();
 auth: {

} strategy: 'jwt',

},


handler: function (request, reply) {

[Link]({}).exec().then(users => {

• candidates ‘open’ route reply(users);

}).catch(err => {

reply([Link]('error accessing db'));

• getUser ‘closed’ route },

});


};
DonationService - login/logout

login(email, password) {

• Login defers to const user = {

email: email,

asyncHttpClient };

password: password


[Link]('/api/users/authenticate', user);

}

• Logout asks asks 

logout() {

asyncHttpClient const status = {

success: false,

to clear the JWT, message: ''

};

and then [Link]();

[Link](new LoginStatus(new LoginStatus(status)));

broadcasts new }

status
• A html5 standard way for web pages to store
named key/value pairs locally, within the client web
Local
browser. Storage
• Like cookies, this data persists even after you
navigate away from the web site, close your
browser tab, exit your browser.

• Unlike cookies, this data is never transmitted to the


remote web server (unless you send it manually)

Inspect it using
developer tools
Storing Tokens in Local Storage

• donation authenticate(url, user) {


name
[Link](url, user).then(response => {

const status = [Link];

if ([Link]) {

value pair [Link] = [Link]([Link]);

[Link](configuration => {

created [Link]('Authorization',
'bearer ' + [Link]);

in local }

});


storage ...

}
Check LocalStorage for Tokens

• If token is
found: isAuthenticated() {

let authenticated = false;

if ([Link] !== 'null') {

• set the token authenticated = true;

[Link](http => {


as an const auth = [Link]([Link]);



[Link]('Authorization', 'bearer ' + [Link]);

});

‘Authorization’ }

return authenticated;

header for }

subsequent
api requests
On App Startup…

• Check to see if export class App {


token is present… ...


attached() {

if ([Link]()) {

• … if it is, bypass [Link]('home').then(() => {

[Link]('dashboard');

login/signup routes });

}

and go straight to }

}
‘home’ router

Common questions

Powered by AI

A potential improvement to the JWT-based authentication system could be integrating token expiration handling. Currently, there is no mention of verifying token expiration before use. Implementing expiration checks would improve security by ensuring tokens are still valid during each request, reducing the risk of session hijacking if tokens are compromised. This could be achieved by decoding the JWT on each request to check the 'exp' claim and refreshing the token if necessary through a silent re-authentication process, keeping user experience seamless while maintaining security .

LoginStatus event publishing enhances user experience by providing real-time feedback on authentication state changes. When a user logs in or out, LoginStatus events allow UI components to react promptly, updating the interface to reflect the user's authentication status (e.g., unlocking access to restricted content or hiding login forms). This seamless transition between states reduces user confusion and assures them that their actions have been recognized by the system, leading to a more intuitive and responsive application experience .

The EventAggregator acts as a central hub for broadcasting and subscribing to events, such as LoginStatus changes. In Aurelia, EventAggregator facilitates managing authentication flows by allowing services to publish events when user authentication states change. When a user successfully logs in or out, the AsyncHttpClient publishes a LoginStatus event, which other components can subscribe to in order to update views or application state accordingly. This decouples different parts of the application, making it more modular and maintainable .

Local Storage is used to persist the JWT across browser sessions by storing the token as a key/value pair locally on the client's browser. This stored token allows the application to maintain authentication state even after navigating away, closing a browser tab, or restarting the browser. When the application starts, it checks Local Storage for the token to determine if a user is already authenticated, allowing the app to bypass the login and navigate directly to protected routes if the token is valid .

The AsyncHttpClient service handles JWT authentication by first posting user credentials to the donation service. If the credentials are correct, it retrieves a JWT from the server and configures the HttpClient to include the token in the Authorization header for all subsequent API requests. The service also publishes a LoginStatus event, which can be used to trigger client-side actions depending on whether authentication succeeded or failed . Upon logout, the Authorization header is cleared, and a new LoginStatus event is published to update the application state .

The primary advantage of using HttpClient configuration to manage authentication headers is streamlined request handling, where the Authorization header can be set across all requests uniformly. This consistent configuration reduces manual task repetitions and potential errors in individual request setups. The potential drawback is that if the configuration isn't properly cleared on logout or error, subsequent unauthenticated requests could inadvertently include a stale or invalid JWT, potentially leading to security issues or user frustration .

The DonationService manages user access by distinguishing open and closed routes. For the open 'candidates' route, the service does not require authentication. However, for the closed 'getUser' route, it employs JWT strategy for authentication. It uses the AsyncHttpClient for login operations, obtaining a JWT which is required for accessing secured routes. This separation of open and closed routes enables the service to control access based on authentication tokens .

In the donation-web and donation-client setup, the components rely on AsyncHttpClient for handling authentication processes. The login function within DonationService delegates authentication to AsyncHttpClient, which manages the API post requests to verify user credentials and retrieve the JWT. For logout, the DonationService instructs AsyncHttpClient to clear authentication headers, which ensures that the client's state is properly reset, preventing unauthorized access. This integration simplifies authentication-related tasks, providing consistent and centralized handling of JWTs across components .

The isAuthenticated function checks for a token in Local Storage to determine if a user session is active. If a token is present and valid, the function configures the HttpClient to include the JWT in the Authorization header for subsequent requests. This mechanism facilitates session management by allowing the application to bypass login routes and directly navigate to protected areas (e.g., 'home' or 'dashboard') if the user is still authenticated upon app startup .

Storing JWT tokens in Local Storage poses security risks, primarily due to vulnerability to XSS attacks. If an attacker manages to inject malicious scripts into the application, tokens in Local Storage can be accessed and potentially exfiltrated, leading to unauthorized access. Unlike cookies, tokens in Local Storage are not automatically sent in HTTP requests, reducing exposure to CSRF attacks but still requiring developers to ensure that no malicious scripts can execute in the context of the authenticated application . Proper application security measures like CSP headers and rigorous input validation are critical to mitigate these risks.

You might also like