@geekbears/gb-ngrx-auth-basic
v17.1.15
Published
This library provides a robust and highly configurable solution for authentication and authorization in Angular applications, leveraging NgRx for state management. It offers a flexible service (`AuthenticationService`) and routing guards, designed to inte
Readme
GbNgrxAuthBasic
This library provides a robust and highly configurable solution for authentication and authorization in Angular applications, leveraging NgRx for state management. It offers a flexible service (AuthenticationService) and routing guards, designed to integrate seamlessly with your backend APIs and custom logic.
Features
- Comprehensive Authentication & Authorization: Handles user login, signup, logout, session refresh, and user data fetching.
- NgRx State Management: Manages authentication state (e.g., token, user, session status) in a way that can be easily integrated with NgRx stores.
- Extensive Customization: Fully configurable via
AuthenticationNgRxModuleConfig, allowing you to tailor API endpoints, request/response handling, user mapping, and more. - Flexible Storage: Supports default
localStoragefor tokens and user data, with an option to provide custom storage solutions. - Device Information: Automatically captures and can include device information in authentication requests.
- Built-in Guards: Provides guards for route protection based on authentication status and role-based access control (RBAC).
- Token Refresh: Manages automatic token refreshing via interceptors.
- Account Management: Includes functionality for fetching user information and deleting accounts.
Installation
To install this library, run the following command:
npm install @gb-ngrx-auth-basicOr if you are using yarn:
yarn add @gb-ngrx-auth-basicPeer Dependencies
This library depends on the @geekbears/gb-ngrx-stack-base package. Ensure it is installed in your project:
npm install @geekbears/gb-ngrx-stack-baseUsage
Module Setup and Configuration
Import GbNgrxAuthBasicModule into your application's root module or a feature module. You must provide the AUTHENTICATION_NGRX_MODULE_CONFIG token with your specific configuration.
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { RouterModule } from '@angular/router';
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { GbNgrxAuthBasicModule, AUTHENTICATION_NGRX_MODULE_CONFIG, AuthenticationNgRxModuleConfig } from 'gb-ngrx-auth-basic'; // Adjust import path if necessary
// Example custom user mapper
const customUserMapper = (userMap: { [key: string]: any }): Promise<any> => {
// Transform userMap into your application's User model
return Promise.resolve({ ...userMap, customField: 'mapped' });
};
// Example custom login response parser
const customLoginResponseParser = async (response: any): Promise<any> => {
// Parse the raw API response to extract AuthenticationData
return {
token: response.data.token,
refreshToken: response.data.refreshToken,
user: response.data.user, // Assuming user object is directly available
};
};
const appConfig: AuthenticationNgRxModuleConfig = {
// --- API Endpoints ---
loginApiUrl: () => '/api/auth/login',
signupApiUrl: () => '/api/auth/signup',
logoutApiUrl: (authData) => `/api/auth/logout?token=${authData.token}`, // Example with authData
refreshTokenApiUri: () => '/api/auth/refresh',
fetchUserInformationAPIendpoint: (data) => `/api/users/${data.user.id}`, // Example using user ID from session
deleteAccountAPIendpoint: (userId) => `/api/users/${userId}`,
// --- Custom Mappers & Parsers ---
customLoginRequestMapper: async (email, password, deviceInfo) => {
return {
email,
password,
device: deviceInfo ? deviceInfo.toMap() : undefined,
customParam: 'example',
};
},
customLoginResponseParser: customLoginResponseParser,
customSignupRequestMapper: async (payload) => {
return payload.toMap(); // Assuming AuthSignupPayload has a toMap method
},
customSignupResponseParser: customLoginResponseParser, // Can reuse if response structure is similar
customLogoutRequestMapper: async (authData) => {
return { authorization: authData.token };
},
customRefreshTokenRequestMapper: async (authData) => {
return { refreshToken: authData.refreshToken };
},
customRefreshTokenResponseParser: customLoginResponseParser, // Can reuse if response structure is similar
customUserMapper: customUserMapper,
customFetchUserInformationResponseMapper: async (data) => {
// If fetchUserInformationAPIendpoint returns data that needs further mapping before customUserMapper
return data.userProfile; // Example: extract user profile from a nested object
},
// --- Route Guard Redirection ---
basicAuthGuardRedirect: (authData, router, route, snapshot) => {
// Example: Redirect to login if not authenticated
if (!authData) {
return router.createUrlTree(['/login']);
}
return of(true); // Allow access
},
roleBasedGuardRedirect: (authData, router, route, snapshot) => {
// Example: Redirect to unauthorized page if role is insufficient
if (authData && !authData.user.roles.includes(route.data['roles'][0])) {
return router.createUrlTree(['/unauthorized']);
}
return of(true); // Allow access
},
onAuthenticatedGuardRedirect: (authData, router, route) => {
// Example: Redirect to dashboard if already authenticated
if (authData && authData.user) {
return router.createUrlTree(['/dashboard']);
}
return of(true); // Allow access
},
onAuthenticatedChangeRedirect: (authData, router, route) => {
// Example: Redirect to login on logout, dashboard on login
if (!authData) {
return router.createUrlTree(['/login']);
} else {
return router.createUrlTree(['/dashboard']);
}
},
authenticatedChangeRedirectOnSignificant: true, // Default: true
// --- Other Options ---
authenticateOnSignup: true, // Default: true
provideDeviceInfo: true, // Default: true
initialAuthCheckedAfterUserFetch: true,
autoLogoutOnSessionExpired: true, // Default: true
autoLogoutOnUnauthorizedUserInfoFetch: true, // Default: true
};
@NgModule({
imports: [
BrowserModule,
HttpClientModule,
RouterModule.forRoot([]), // Your app routes
StoreModule.forRoot({}), // Your NgRx stores
EffectsModule.forRoot([]), // Your NgRx effects
GbNgrxAuthBasicModule.forRoot(appConfig), // Provide the configuration here
],
// ...
})
export class AppModule { }Authentication Service Methods
Inject AuthenticationService to use its methods.
loginWithCredentials(email: string, password: string): Observable<AuthenticationData>: Initiates the login process. UsesloginApiUrlandcustomLoginRequestMapper/customLoginResponseParserif provided.this.authService.loginWithCredentials('[email protected]', 'password123').subscribe(session => { console.log('Login successful:', session); });signupWithCredentials(payload: AuthSignupPayload): Observable<AuthenticationData>: Handles user registration. UsessignupApiUrlandcustomSignupRequestMapper/customSignupResponseParser. IfauthenticateOnSignupis true, it will attempt to authenticate the user after signup.const signupPayload = new AuthSignupPayload({ email: '[email protected]', password: 'securepassword' }); this.authService.signupWithCredentials(signupPayload).subscribe(session => { console.log('Signup successful:', session); });fetchAuthUserData(): Observable<IUser>: Fetches the current user's detailed information from the backend usingfetchUserInformationAPIendpoint. It usescustomFetchUserInformationResponseMapperandcustomUserMapperfor data transformation.this.authService.fetchAuthUserData().subscribe(user => { console.log('User data:', user); });getAuthenticatedSession(): Observable<AuthenticationData | null>: Retrieves the current authentication session (token, refresh token, user) from storage.getRefreshedSession(refreshToken?: string): Observable<AuthenticationDataModel | null>: Requests a new session token using the refresh token. UsesrefreshTokenApiUriand custom mappers.logout(): Observable<void>: Logs the user out by clearing tokens from storage and optionally calling alogoutApiUrl.deleteAccount(userId: string): Observable<IUser>: Deletes the user account via thedeleteAccountAPIendpoint.
NgRx State Management
This library manages its state using NgRx. You can access the authentication state directly using the provided selectors.
Selectors
Import these from the library to query the store:
isAuthenticatedSelector:Observable<boolean>- Returnstrueif the user is currently authenticated.authenticatedUserSelector:Observable<IUser | null>- Returns the current authenticated user object.authenticationDataSelector:Observable<AuthenticationData | null>- Returns the full authentication session data (tokens, user, etc.).authTokenSelector:Observable<string | undefined>- Returns the current access token.isAuthenticatingSelector:Observable<boolean>- Returnstruewhile a login request is in progress.loginFailureSelector:Observable<Failure | null>- Returns any error that occurred during the last login attempt.isSigningUpSelector:Observable<boolean>- Returnstruewhile a signup request is in progress.signupFailureSelector:Observable<Failure | null>- Returns any error that occurred during the last signup attempt.
Actions
While the AuthenticationService handles most interactions, you can also dispatch actions directly if needed. Actions are available strictly via AuthenticationNgRxActions.
Example:
import { Store } from '@ngrx/store';
import { AuthenticationNgRxActions } from 'gb-ngrx-auth-basic';
constructor(private store: Store) {}
logout() {
this.store.dispatch(AuthenticationNgRxActions.logout());
}Route Guards
The library provides guards that can be configured to redirect users based on authentication status or roles.
BasicAuthGuard: Protects routes requiring authentication. UsesbasicAuthGuardRedirectandonAuthenticatedGuardRedirectfrom the config.RbacGuard: Protects routes based on user roles. UsesroleBasedGuardRedirectandonAuthenticatedGuardRedirectfrom the config.RedirectOnAuthGuard: Can be used to redirect authenticated users away from certain pages (e.g., login page). UsesonAuthenticatedGuardRedirectfrom the config.
Configure the redirection logic within the AuthenticationNgRxModuleConfig object passed to GbNgrxAuthBasicModule.forRoot().
Storage
By default, the library stores authentication tokens, refresh tokens, user data, and device information in localStorage using predefined keys (s_token, s_refreshToken, s_user, s_device_info). You can provide a custom storage implementation by injecting a service bound to CustomInternalStorageToken.
Device Info
If provideDeviceInfo is set to true (default), the library automatically captures device details to include in authentication requests. This helps in tracking and managing user sessions across different devices.
Captured Information:
- ID: A generated UUID that uniquely identifies the browser session.
- Name: A combination of the User Agent string and screen resolution (e.g.,
Mozilla/5.0 ... - (1920 x 1080) 24).
You can customize how this information is sent to your API using the customLoginRequestMapper in the configuration.
Development
This library was generated with Angular CLI version 12.2.1.
Development server
Run ng serve for a dev server. Navigate to http://localhost:4200/. The app will automatically reload if you change any of the source files.
Code scaffolding
Run ng generate component component-name to generate a new component. You can also use ng generate directive|pipe|service|class|guard|interface|enum|module.
Build
Run ng build to build the project. The build artifacts will be stored in the dist/ directory.
Running unit tests
Run ng test to execute the unit tests via Karma.
Running end-to-end tests
Run ng e2e to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
Further help
To get more help on the Angular CLI use ng help or go check out the Angular CLI Overview and Command Reference page.
