@hichchi/ngx-auth 0.0.1-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/hichchi-ngx-auth.mjs +1629 -0
- package/fesm2022/hichchi-ngx-auth.mjs.map +1 -0
- package/index.d.ts +1 -0
- package/lib/auth.module.d.ts +92 -0
- package/lib/components/auth-form/auth-form.component.d.ts +61 -0
- package/lib/components/index.d.ts +1 -0
- package/lib/constants.d.ts +96 -0
- package/lib/directives/index.d.ts +1 -0
- package/lib/directives/permission.directive.d.ts +134 -0
- package/lib/enums/auth-guard-condition.enum.d.ts +38 -0
- package/lib/enums/index.d.ts +1 -0
- package/lib/guards/auth.guard.d.ts +71 -0
- package/lib/guards/index.d.ts +2 -0
- package/lib/guards/role.guard.d.ts +5 -0
- package/lib/index.d.ts +9 -0
- package/lib/interceptors/auth.interceptor.d.ts +101 -0
- package/lib/interceptors/index.d.ts +1 -0
- package/lib/interfaces/auth-config.interface.d.ts +5 -0
- package/lib/interfaces/auth-form-data.interface.d.ts +61 -0
- package/lib/interfaces/auth-guard-option.interface.d.ts +72 -0
- package/lib/interfaces/index.d.ts +3 -0
- package/lib/services/auth.service.d.ts +328 -0
- package/lib/services/index.d.ts +1 -0
- package/lib/state/auth.state.d.ts +155 -0
- package/lib/state/index.d.ts +1 -0
- package/lib/tokens.d.ts +73 -0
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/route.utils.d.ts +100 -0
- package/package.json +42 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import { HttpClient } from "@angular/common/http";
|
|
2
|
+
import { Observable } from "rxjs";
|
|
3
|
+
import { AccessToken, AuthResponse, RefreshToken, SignInBody, SignUpBody, TokenResponse, User } from "@hichchi/nest-connector/auth";
|
|
4
|
+
import { SuccessResponse } from "@hichchi/nest-connector";
|
|
5
|
+
import { AuthConfig } from "../interfaces";
|
|
6
|
+
import * as i0 from "@angular/core";
|
|
7
|
+
/**
|
|
8
|
+
* Angular authentication service for client-side authentication operations
|
|
9
|
+
*
|
|
10
|
+
* This service provides methods for handling authentication operations in Angular applications,
|
|
11
|
+
* including user sign-in, sign-up, Google OAuth authentication, token management, and sign-out.
|
|
12
|
+
* It communicates with the backend authentication API and handles the client-side aspects
|
|
13
|
+
* of the authentication flow.
|
|
14
|
+
*
|
|
15
|
+
* The service is configured through the AuthConfig interface and automatically handles
|
|
16
|
+
* token expiration date parsing and HTTP request management. It integrates seamlessly
|
|
17
|
+
* with the @hichchi/nest-auth backend module.
|
|
18
|
+
*
|
|
19
|
+
* Key features:
|
|
20
|
+
* - Local authentication (email/username and password)
|
|
21
|
+
* - Google OAuth authentication with popup flow
|
|
22
|
+
* - Token refresh functionality
|
|
23
|
+
* - User registration
|
|
24
|
+
* - Automatic token expiration handling
|
|
25
|
+
* - RESTful API communication
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* // In a component
|
|
30
|
+
* export class LoginComponent {
|
|
31
|
+
* constructor(private authService: AuthService) {}
|
|
32
|
+
*
|
|
33
|
+
* async signIn() {
|
|
34
|
+
* try {
|
|
35
|
+
* const response = await this.authService.signIn({
|
|
36
|
+
* email: 'user@example.com',
|
|
37
|
+
* password: 'password123'
|
|
38
|
+
* }).toPromise();
|
|
39
|
+
* console.log('Signed in:', response.user);
|
|
40
|
+
* } catch (error) {
|
|
41
|
+
* console.error('Sign in failed:', error);
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @see {@link AuthConfig} Configuration interface for the authentication service
|
|
48
|
+
* @see {@link NgxHichchiAuthModule} Module that provides this service
|
|
49
|
+
* @see {@link AuthState} State management service for authentication
|
|
50
|
+
* @see {@link AuthResponse} Response interface for authentication operations
|
|
51
|
+
*/
|
|
52
|
+
export declare class AuthService {
|
|
53
|
+
private readonly http;
|
|
54
|
+
private readonly config;
|
|
55
|
+
/**
|
|
56
|
+
* Creates an instance of AuthService
|
|
57
|
+
*
|
|
58
|
+
* @param http - Http client
|
|
59
|
+
* @param config - The authentication configuration injected from AUTH_CONFIG token
|
|
60
|
+
*
|
|
61
|
+
* @see {@link AUTH_CONFIG} Injection token for authentication configuration
|
|
62
|
+
* @see {@link AuthConfig} Interface defining the configuration structure
|
|
63
|
+
*/
|
|
64
|
+
constructor(http: HttpClient, config: AuthConfig);
|
|
65
|
+
/**
|
|
66
|
+
* Authenticates a user with email/username and password
|
|
67
|
+
*
|
|
68
|
+
* This method sends a sign-in request to the backend authentication API with the provided
|
|
69
|
+
* credentials. It automatically converts the token expiration timestamps from the response
|
|
70
|
+
* into JavaScript Date objects for easier handling in the client application.
|
|
71
|
+
*
|
|
72
|
+
* @param dto - The sign-in data containing user credentials
|
|
73
|
+
* @returns Observable that emits the authentication response with user data and tokens
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* // Sign in with email and password
|
|
78
|
+
* this.authService.signIn({
|
|
79
|
+
* email: 'user@example.com',
|
|
80
|
+
* password: 'password123'
|
|
81
|
+
* }).subscribe({
|
|
82
|
+
* next: (response) => {
|
|
83
|
+
* console.log('User signed in:', response.user);
|
|
84
|
+
* console.log('Access token expires:', response.accessTokenExpiresOn);
|
|
85
|
+
* },
|
|
86
|
+
* error: (error) => {
|
|
87
|
+
* console.error('Sign in failed:', error);
|
|
88
|
+
* }
|
|
89
|
+
* });
|
|
90
|
+
* ```
|
|
91
|
+
*
|
|
92
|
+
* @see {@link SignInBody} Interface for sign-in request data
|
|
93
|
+
* @see {@link AuthResponse} Interface for authentication response
|
|
94
|
+
* @see {@link AuthEndpoint.SIGN_IN} Backend endpoint for user authentication
|
|
95
|
+
*/
|
|
96
|
+
signIn(dto: SignInBody): Observable<AuthResponse>;
|
|
97
|
+
/**
|
|
98
|
+
* Initiates Google OAuth authentication using a popup window
|
|
99
|
+
*
|
|
100
|
+
* This method opens a popup window that navigates to the Google OAuth authentication
|
|
101
|
+
* endpoint. It handles the OAuth flow by monitoring the popup window and extracting
|
|
102
|
+
* the access token from the callback URL when authentication is successful.
|
|
103
|
+
*
|
|
104
|
+
* The popup is automatically positioned in the center of the screen and has predefined
|
|
105
|
+
* dimensions for optimal user experience. The method polls the popup window to detect
|
|
106
|
+
* when authentication is complete or if the user closes the popup.
|
|
107
|
+
*
|
|
108
|
+
* @returns Promise that resolves with the access token when authentication succeeds
|
|
109
|
+
*
|
|
110
|
+
* @throws {Error} If authentication fails or the popup is blocked
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* // Initiate Google sign-in
|
|
115
|
+
* try {
|
|
116
|
+
* const accessToken = await this.authService.googleSignIn();
|
|
117
|
+
* console.log('Google authentication successful:', accessToken);
|
|
118
|
+
*
|
|
119
|
+
* // Use the token to get full auth response
|
|
120
|
+
* const authResponse = await this.authService.getAuthResponse(accessToken).toPromise();
|
|
121
|
+
* console.log('User data:', authResponse.user);
|
|
122
|
+
* } catch (error) {
|
|
123
|
+
* console.error('Google authentication failed:', error);
|
|
124
|
+
* }
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* // In a component with error handling
|
|
130
|
+
* async signInWithGoogle() {
|
|
131
|
+
* try {
|
|
132
|
+
* const token = await this.authService.googleSignIn();
|
|
133
|
+
* // Handle successful authentication
|
|
134
|
+
* this.router.navigate(['/dashboard']);
|
|
135
|
+
* } catch (error) {
|
|
136
|
+
* if (error.message.includes('popup')) {
|
|
137
|
+
* this.showError('Please allow popups for Google sign-in');
|
|
138
|
+
* } else {
|
|
139
|
+
* this.showError('Google sign-in failed. Please try again.');
|
|
140
|
+
* }
|
|
141
|
+
* }
|
|
142
|
+
* }
|
|
143
|
+
* ```
|
|
144
|
+
*
|
|
145
|
+
* @see {@link getAuthResponse} Method to get full authentication response using the access token
|
|
146
|
+
* @see {@link AuthEndpoint.GOOGLE_SIGN_IN} Backend endpoint for Google OAuth initiation
|
|
147
|
+
* @see {@link GOOGLE_AUTH_POPUP_WIDTH} Constant defining popup window width
|
|
148
|
+
* @see {@link GOOGLE_AUTH_POPUP_HEIGHT} Constant defining popup window height
|
|
149
|
+
* @see {@link POPUP_POLLING_INTERVAL_MS} Constant defining popup polling interval
|
|
150
|
+
*/
|
|
151
|
+
googleSignIn(): Promise<AccessToken>;
|
|
152
|
+
/**
|
|
153
|
+
* Retrieves the complete authentication response using an access token
|
|
154
|
+
*
|
|
155
|
+
* This method exchanges an access token for a complete authentication response
|
|
156
|
+
* containing user information and token details. It's typically used after
|
|
157
|
+
* Google OAuth authentication to get the full user profile and session data.
|
|
158
|
+
*
|
|
159
|
+
* The method automatically converts token expiration timestamps to JavaScript
|
|
160
|
+
* Date objects for easier handling in the client application.
|
|
161
|
+
*
|
|
162
|
+
* @param accessToken - The access token to exchange for authentication response
|
|
163
|
+
* @returns Observable that emits the complete authentication response
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```typescript
|
|
167
|
+
* // Get auth response after Google sign-in
|
|
168
|
+
* const accessToken = await this.authService.googleSignIn();
|
|
169
|
+
* this.authService.getAuthResponse(accessToken).subscribe({
|
|
170
|
+
* next: (response) => {
|
|
171
|
+
* console.log('User:', response.user);
|
|
172
|
+
* console.log('Tokens:', {
|
|
173
|
+
* access: response.accessToken,
|
|
174
|
+
* refresh: response.refreshToken
|
|
175
|
+
* });
|
|
176
|
+
* },
|
|
177
|
+
* error: (error) => {
|
|
178
|
+
* console.error('Failed to get auth response:', error);
|
|
179
|
+
* }
|
|
180
|
+
* });
|
|
181
|
+
* ```
|
|
182
|
+
*
|
|
183
|
+
* @see {@link AccessToken} Type representing access tokens
|
|
184
|
+
* @see {@link AuthResponse} Interface for complete authentication response
|
|
185
|
+
* @see {@link AuthEndpoint.GET_AUTH_RESPONSE} Backend endpoint for token exchange
|
|
186
|
+
* @see {@link googleSignIn} Method that provides access tokens for this operation
|
|
187
|
+
*/
|
|
188
|
+
getAuthResponse(accessToken: AccessToken): Observable<AuthResponse>;
|
|
189
|
+
/**
|
|
190
|
+
* Registers a new user account
|
|
191
|
+
*
|
|
192
|
+
* This method sends a registration request to the backend API with the provided
|
|
193
|
+
* user information. It creates a new user account and returns the user data
|
|
194
|
+
* upon successful registration.
|
|
195
|
+
*
|
|
196
|
+
* Note that this method only creates the user account and does not automatically
|
|
197
|
+
* sign the user in. After successful registration, you may need to call signIn
|
|
198
|
+
* or handle email verification depending on your application's configuration.
|
|
199
|
+
*
|
|
200
|
+
* @param dto - The sign-up data containing user registration information
|
|
201
|
+
* @returns Observable that emits the newly created user data
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```typescript
|
|
205
|
+
* // Register a new user
|
|
206
|
+
* this.authService.signUp({
|
|
207
|
+
* email: 'newuser@example.com',
|
|
208
|
+
* password: 'securePassword123',
|
|
209
|
+
* firstName: 'John',
|
|
210
|
+
* lastName: 'Doe'
|
|
211
|
+
* }).subscribe({
|
|
212
|
+
* next: (user) => {
|
|
213
|
+
* console.log('User registered successfully:', user);
|
|
214
|
+
* // Optionally redirect to sign-in or email verification page
|
|
215
|
+
* this.router.navigate(['/verify-email']);
|
|
216
|
+
* },
|
|
217
|
+
* error: (error) => {
|
|
218
|
+
* console.error('Registration failed:', error);
|
|
219
|
+
* // Handle registration errors (email already exists, etc.)
|
|
220
|
+
* }
|
|
221
|
+
* });
|
|
222
|
+
* ```
|
|
223
|
+
*
|
|
224
|
+
* @see {@link SignUpBody} Interface for user registration data
|
|
225
|
+
* @see {@link User} Interface for user data returned after registration
|
|
226
|
+
* @see {@link AuthEndpoint.SIGN_UP} Backend endpoint for user registration
|
|
227
|
+
* @see {@link signIn} Method to authenticate user after registration
|
|
228
|
+
*/
|
|
229
|
+
signUp(dto: SignUpBody): Observable<User>;
|
|
230
|
+
/**
|
|
231
|
+
* Refreshes an expired access token using a refresh token
|
|
232
|
+
*
|
|
233
|
+
* This method exchanges a valid refresh token for a new set of access and refresh tokens.
|
|
234
|
+
* It's typically used when the current access token has expired but the refresh token
|
|
235
|
+
* is still valid, allowing the user to maintain their session without re-authenticating.
|
|
236
|
+
*
|
|
237
|
+
* The refresh token mechanism provides a secure way to maintain long-lived sessions
|
|
238
|
+
* while keeping access tokens short-lived for better security.
|
|
239
|
+
*
|
|
240
|
+
* @param refreshToken - The refresh token to exchange for new tokens
|
|
241
|
+
* @returns Observable that emits the new token response
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* ```typescript
|
|
245
|
+
* // Refresh tokens when access token expires
|
|
246
|
+
* const storedRefreshToken = localStorage.getItem('refreshToken');
|
|
247
|
+
* if (storedRefreshToken) {
|
|
248
|
+
* this.authService.refreshToken(storedRefreshToken).subscribe({
|
|
249
|
+
* next: (tokenResponse) => {
|
|
250
|
+
* console.log('Tokens refreshed successfully');
|
|
251
|
+
* // Store new tokens
|
|
252
|
+
* localStorage.setItem('accessToken', tokenResponse.accessToken);
|
|
253
|
+
* localStorage.setItem('refreshToken', tokenResponse.refreshToken);
|
|
254
|
+
* },
|
|
255
|
+
* error: (error) => {
|
|
256
|
+
* console.error('Token refresh failed:', error);
|
|
257
|
+
* // Redirect to login page
|
|
258
|
+
* this.router.navigate(['/login']);
|
|
259
|
+
* }
|
|
260
|
+
* });
|
|
261
|
+
* }
|
|
262
|
+
* ```
|
|
263
|
+
*
|
|
264
|
+
* @see {@link RefreshToken} Type representing refresh tokens
|
|
265
|
+
* @see {@link TokenResponse} Interface for token refresh response
|
|
266
|
+
* @see {@link AuthEndpoint.REFRESH_TOKEN} Backend endpoint for token refresh
|
|
267
|
+
* @see {@link signIn} Method to get initial tokens through authentication
|
|
268
|
+
*/
|
|
269
|
+
refreshToken(refreshToken: RefreshToken): Observable<TokenResponse>;
|
|
270
|
+
/**
|
|
271
|
+
* Signs out the current user and invalidates their session
|
|
272
|
+
*
|
|
273
|
+
* This method sends a sign-out request to the backend API to invalidate the user's
|
|
274
|
+
* current session and tokens. It effectively logs the user out of the application
|
|
275
|
+
* and clears their authentication state on the server.
|
|
276
|
+
*
|
|
277
|
+
* After calling this method, you should also clear any client-side authentication
|
|
278
|
+
* data such as tokens stored in localStorage, sessionStorage, or application state.
|
|
279
|
+
*
|
|
280
|
+
* @returns Observable that emits a success response when sign-out is complete
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```typescript
|
|
284
|
+
* // Sign out the current user
|
|
285
|
+
* this.authService.signOut().subscribe({
|
|
286
|
+
* next: (response) => {
|
|
287
|
+
* console.log('User signed out successfully');
|
|
288
|
+
* // Clear client-side authentication data
|
|
289
|
+
* localStorage.removeItem('accessToken');
|
|
290
|
+
* localStorage.removeItem('refreshToken');
|
|
291
|
+
* // Redirect to login page
|
|
292
|
+
* this.router.navigate(['/login']);
|
|
293
|
+
* },
|
|
294
|
+
* error: (error) => {
|
|
295
|
+
* console.error('Sign out failed:', error);
|
|
296
|
+
* // Even if server sign-out fails, clear local data
|
|
297
|
+
* localStorage.clear();
|
|
298
|
+
* this.router.navigate(['/login']);
|
|
299
|
+
* }
|
|
300
|
+
* });
|
|
301
|
+
* ```
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```typescript
|
|
305
|
+
* // Sign out with state management
|
|
306
|
+
* async signOut() {
|
|
307
|
+
* try {
|
|
308
|
+
* await this.authService.signOut().toPromise();
|
|
309
|
+
* // Clear authentication state
|
|
310
|
+
* this.authState.clearUser();
|
|
311
|
+
* this.notificationService.showSuccess('Signed out successfully');
|
|
312
|
+
* } catch (error) {
|
|
313
|
+
* console.error('Sign out error:', error);
|
|
314
|
+
* } finally {
|
|
315
|
+
* // Always redirect to login
|
|
316
|
+
* this.router.navigate(['/login']);
|
|
317
|
+
* }
|
|
318
|
+
* }
|
|
319
|
+
* ```
|
|
320
|
+
*
|
|
321
|
+
* @see {@link SuccessResponse} Interface for success response
|
|
322
|
+
* @see {@link AuthEndpoint.SIGN_OUT} Backend endpoint for user sign-out
|
|
323
|
+
* @see {@link signIn} Method to authenticate user after sign-out
|
|
324
|
+
*/
|
|
325
|
+
signOut(): Observable<SuccessResponse | null>;
|
|
326
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<AuthService, never>;
|
|
327
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<AuthService>;
|
|
328
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./auth.service";
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { Observable } from "rxjs";
|
|
2
|
+
import { AccessToken, AuthResponse, RefreshToken, SignInBody, TokenResponse, User } from "@hichchi/nest-connector/auth";
|
|
3
|
+
import { SuccessResponse } from "@hichchi/nest-connector";
|
|
4
|
+
/**
|
|
5
|
+
* Interface defining the authentication state model
|
|
6
|
+
*
|
|
7
|
+
* This interface represents the complete authentication state structure used
|
|
8
|
+
* throughout the Angular application. It contains user information, authentication
|
|
9
|
+
* tokens, and session data that persists across browser sessions.
|
|
10
|
+
*
|
|
11
|
+
* The state is automatically synchronized with browser storage to maintain
|
|
12
|
+
* authentication across page refreshes and browser restarts.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* // Accessing state in a component
|
|
17
|
+
* export class HeaderComponent {
|
|
18
|
+
* private authState = inject(AuthState)
|
|
19
|
+
*
|
|
20
|
+
* get isSignedIn() {
|
|
21
|
+
* return this.authState.signedIn();
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* get currentUser() {
|
|
25
|
+
* return this.authState.user();
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @see {@link AuthState} The signal store that manages this state
|
|
31
|
+
* @see {@link User} Interface for user data
|
|
32
|
+
* @see {@link AccessToken} Type for access tokens
|
|
33
|
+
* @see {@link RefreshToken} Type for refresh tokens
|
|
34
|
+
*/
|
|
35
|
+
export interface AuthStateModel {
|
|
36
|
+
/** Whether the user is currently signed in */
|
|
37
|
+
signedIn: boolean;
|
|
38
|
+
/** Unique identifier for the current session */
|
|
39
|
+
sessionId: string | null;
|
|
40
|
+
/** Current authenticated user information */
|
|
41
|
+
user: User | null;
|
|
42
|
+
/** JWT access token for API authentication */
|
|
43
|
+
accessToken: AccessToken | null;
|
|
44
|
+
/** JWT refresh token for obtaining new access tokens */
|
|
45
|
+
refreshToken: RefreshToken | null;
|
|
46
|
+
/** Expiration date of the access token */
|
|
47
|
+
accessTokenExpiresOn: Date | null;
|
|
48
|
+
/** Expiration date of the refresh token */
|
|
49
|
+
refreshTokenExpiresOn: Date | null;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Authentication state management store using NgRx Signals
|
|
53
|
+
*
|
|
54
|
+
* This signal store provides centralized state management for authentication in Angular applications.
|
|
55
|
+
* It manages user authentication state, tokens, and provides methods for authentication operations.
|
|
56
|
+
* The store automatically persists state to browser storage and provides reactive computed values.
|
|
57
|
+
*
|
|
58
|
+
* Key features:
|
|
59
|
+
* - Automatic state persistence with browser storage sync
|
|
60
|
+
* - Reactive computed properties for common authentication checks
|
|
61
|
+
* - Built-in methods for sign-in, sign-out, and token management
|
|
62
|
+
* - Integration with Angular Router for navigation after authentication
|
|
63
|
+
* - Type-safe state management with TypeScript
|
|
64
|
+
*
|
|
65
|
+
* The store is provided at the root level and can be injected into any component or service.
|
|
66
|
+
* It uses NgRx Signals for reactive state management and provides a modern alternative
|
|
67
|
+
* to traditional NgRx store patterns.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* // In a component
|
|
72
|
+
* export class AppComponent {
|
|
73
|
+
* private authState = inject(AuthState)
|
|
74
|
+
*
|
|
75
|
+
* // Access reactive state
|
|
76
|
+
* isSignedIn = this.authState.signedIn;
|
|
77
|
+
* currentUser = this.authState.user;
|
|
78
|
+
* hasAccessToken = this.authState.hasAccessToken;
|
|
79
|
+
*
|
|
80
|
+
* // Sign in user
|
|
81
|
+
* async signIn() {
|
|
82
|
+
* this.authState.signIn({
|
|
83
|
+
* email: 'user@example.com',
|
|
84
|
+
* password: 'password123'
|
|
85
|
+
* }, '/dashboard').subscribe({
|
|
86
|
+
* next: (response) => console.log('Signed in:', response.user),
|
|
87
|
+
* error: (error) => console.error('Sign in failed:', error)
|
|
88
|
+
* });
|
|
89
|
+
* }
|
|
90
|
+
*
|
|
91
|
+
* // Sign out user
|
|
92
|
+
* signOut() {
|
|
93
|
+
* this.authState.signOut('/login').subscribe();
|
|
94
|
+
* }
|
|
95
|
+
* }
|
|
96
|
+
* ```
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* // In a guard
|
|
101
|
+
* export class AuthGuard {
|
|
102
|
+
* private authState = inject(AuthState)
|
|
103
|
+
*
|
|
104
|
+
* canActivate(): boolean {
|
|
105
|
+
* return this.authState.signedIn() && this.authState.hasAccessToken();
|
|
106
|
+
* }
|
|
107
|
+
* }
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```typescript
|
|
112
|
+
* // Using computed properties
|
|
113
|
+
* export class HeaderComponent {
|
|
114
|
+
* private authState = inject(AuthState)
|
|
115
|
+
*
|
|
116
|
+
* // Reactive computed values
|
|
117
|
+
* userRole = this.authState.role;
|
|
118
|
+
* isEmailVerified = this.authState.emailVerified;
|
|
119
|
+
* hasValidToken = this.authState.hasAccessToken;
|
|
120
|
+
* }
|
|
121
|
+
* ```
|
|
122
|
+
*
|
|
123
|
+
* @see {@link AuthStateModel} Interface defining the state structure
|
|
124
|
+
* @see {@link AuthService} Service used for authentication operations
|
|
125
|
+
* @see {@link signalStore} NgRx Signals store factory function
|
|
126
|
+
* @see {@link withStorageSync} Storage synchronization feature
|
|
127
|
+
*/
|
|
128
|
+
export declare const AuthState: import("@angular/core").Type<{
|
|
129
|
+
signedIn: import("@angular/core").Signal<boolean>;
|
|
130
|
+
sessionId: import("@angular/core").Signal<string | null>;
|
|
131
|
+
user: import("@angular/core").Signal<User<string, string> | null>;
|
|
132
|
+
accessToken: import("@angular/core").Signal<AccessToken | null>;
|
|
133
|
+
refreshToken: import("@angular/core").Signal<RefreshToken | null>;
|
|
134
|
+
accessTokenExpiresOn: import("@angular/core").Signal<Date | null>;
|
|
135
|
+
refreshTokenExpiresOn: import("@angular/core").Signal<Date | null>;
|
|
136
|
+
hasAccessToken: import("@angular/core").Signal<boolean>;
|
|
137
|
+
role: import("@angular/core").Signal<string | import("@hichchi/nest-connector/auth").Role<string, string> | null | undefined>;
|
|
138
|
+
emailVerified: import("@angular/core").Signal<boolean>;
|
|
139
|
+
clearStorage: () => void;
|
|
140
|
+
readFromStorage: () => void;
|
|
141
|
+
writeToStorage: () => void;
|
|
142
|
+
reset: () => void;
|
|
143
|
+
setTokens: (tokenResponse: TokenResponse) => void;
|
|
144
|
+
signIn: (signInBody: SignInBody, redirect?: string | ((res: AuthResponse) => string)) => Observable<AuthResponse>;
|
|
145
|
+
authenticateWithToken: (accessToken: AccessToken, redirect?: string | ((res: AuthResponse) => string)) => Observable<AuthResponse>;
|
|
146
|
+
signOut: (redirect?: string) => Observable<SuccessResponse | null>;
|
|
147
|
+
} & import("@ngrx/signals").StateSource<{
|
|
148
|
+
signedIn: boolean;
|
|
149
|
+
sessionId: string | null;
|
|
150
|
+
user: User | null;
|
|
151
|
+
accessToken: AccessToken | null;
|
|
152
|
+
refreshToken: RefreshToken | null;
|
|
153
|
+
accessTokenExpiresOn: Date | null;
|
|
154
|
+
refreshTokenExpiresOn: Date | null;
|
|
155
|
+
}>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./auth.state";
|
package/lib/tokens.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Injection token for authentication configuration
|
|
3
|
+
*
|
|
4
|
+
* This constant defines the injection token used by Angular's dependency injection
|
|
5
|
+
* system to provide authentication configuration throughout the ngx-auth module.
|
|
6
|
+
* It allows the AuthConfig interface to be injected into services and components
|
|
7
|
+
* that need access to authentication settings.
|
|
8
|
+
*
|
|
9
|
+
* The token is used internally by the NgxHichchiAuthModule.forRoot() method to
|
|
10
|
+
* register the authentication configuration as a provider, making it available
|
|
11
|
+
* for injection in services like AuthService.
|
|
12
|
+
*
|
|
13
|
+
* This follows Angular's recommended pattern for providing configuration objects
|
|
14
|
+
* to libraries and modules, ensuring type safety and proper dependency injection.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* // Used internally by the module to provide configuration
|
|
19
|
+
* @NgModule({
|
|
20
|
+
* providers: [
|
|
21
|
+
* { provide: AUTH_CONFIG, useValue: config },
|
|
22
|
+
* AuthService
|
|
23
|
+
* ]
|
|
24
|
+
* })
|
|
25
|
+
* export class NgxHichchiAuthModule {
|
|
26
|
+
* static forRoot(config: AuthConfig): ModuleWithProviders<NgxHichchiAuthModule> {
|
|
27
|
+
* return {
|
|
28
|
+
* ngModule: NgxHichchiAuthModule,
|
|
29
|
+
* providers: [
|
|
30
|
+
* { provide: AUTH_CONFIG, useValue: config },
|
|
31
|
+
* provideHttpClient(),
|
|
32
|
+
* AuthService
|
|
33
|
+
* ]
|
|
34
|
+
* };
|
|
35
|
+
* }
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* // Injecting the configuration in a service
|
|
42
|
+
* @Injectable()
|
|
43
|
+
* export class AuthService {
|
|
44
|
+
* constructor(
|
|
45
|
+
* @Inject(AUTH_CONFIG) private readonly config: AuthConfig
|
|
46
|
+
* ) {
|
|
47
|
+
* console.log('API Base URL:', this.config.apiBaseURL);
|
|
48
|
+
* console.log('Auth Field:', this.config.authField);
|
|
49
|
+
* }
|
|
50
|
+
* }
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* // Using in a component (though typically not recommended)
|
|
56
|
+
* @Component({
|
|
57
|
+
* selector: 'app-auth-info',
|
|
58
|
+
* template: `<p>API URL: {{ apiUrl }}</p>`
|
|
59
|
+
* })
|
|
60
|
+
* export class AuthInfoComponent {
|
|
61
|
+
* apiUrl: string;
|
|
62
|
+
*
|
|
63
|
+
* constructor(@Inject(AUTH_CONFIG) private config: AuthConfig) {
|
|
64
|
+
* this.apiUrl = config.apiBaseURL;
|
|
65
|
+
* }
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* @see {@link AuthConfig} Interface that defines the structure of the configuration object
|
|
70
|
+
* @see {@link NgxHichchiAuthModule} Module that uses this token to provide configuration
|
|
71
|
+
* @see {@link AuthService} Service that injects this configuration
|
|
72
|
+
*/
|
|
73
|
+
export declare const AUTH_CONFIG = "AUTH_CONFIG";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./route.utils";
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { ActivatedRouteSnapshot } from "@angular/router";
|
|
2
|
+
import { AuthGuardOption } from "../interfaces";
|
|
3
|
+
/**
|
|
4
|
+
* Retrieves all authentication guard options from a route and its parent routes
|
|
5
|
+
*
|
|
6
|
+
* This utility function extracts authentication guard options from the current route
|
|
7
|
+
* and recursively collects options from parent routes in the route hierarchy. It handles
|
|
8
|
+
* the inheritance and merging of guard options, ensuring that parent route guards are
|
|
9
|
+
* applied alongside child route guards.
|
|
10
|
+
*
|
|
11
|
+
* The function implements a hierarchical guard system where:
|
|
12
|
+
* - Child route options take precedence over parent options for the same condition
|
|
13
|
+
* - Parent options are inherited when no conflicting child option exists
|
|
14
|
+
* - Options are collected recursively up the route tree
|
|
15
|
+
* - The final array contains all applicable guard options for the route
|
|
16
|
+
*
|
|
17
|
+
* This enables complex authentication scenarios where different route levels can
|
|
18
|
+
* specify different authentication requirements, with child routes able to override
|
|
19
|
+
* or supplement parent route authentication rules.
|
|
20
|
+
*
|
|
21
|
+
* @param currentRoute - The activated route snapshot to extract guard options from
|
|
22
|
+
* @returns Array of authentication guard options applicable to the route
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* // Route configuration with nested guards
|
|
27
|
+
* const routes: Routes = [
|
|
28
|
+
* {
|
|
29
|
+
* path: 'admin',
|
|
30
|
+
* component: AdminLayoutComponent,
|
|
31
|
+
* canActivate: [authGuard(AuthGuardCondition.SIGNED_IN, true, '/login')],
|
|
32
|
+
* children: [
|
|
33
|
+
* {
|
|
34
|
+
* path: 'users',
|
|
35
|
+
* component: UsersComponent,
|
|
36
|
+
* canActivate: [authGuard(AuthGuardCondition.HAS_TOKEN, true, '/unauthorized')]
|
|
37
|
+
* }
|
|
38
|
+
* ]
|
|
39
|
+
* }
|
|
40
|
+
* ];
|
|
41
|
+
*
|
|
42
|
+
* // In the guard, get all applicable options
|
|
43
|
+
* const allOptions = getAllAuthGuardOptions(route);
|
|
44
|
+
* // Result: [
|
|
45
|
+
* // { condition: 'signed-in', state: true, redirect: '/login' },
|
|
46
|
+
* // { condition: 'has-token', state: true, redirect: '/unauthorized' }
|
|
47
|
+
* // ]
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* // Using in a custom guard implementation
|
|
53
|
+
* export const customAuthGuard: CanActivateFn = (route, state) => {
|
|
54
|
+
* const authState = inject(AuthState);
|
|
55
|
+
* const router = inject(Router);
|
|
56
|
+
*
|
|
57
|
+
* const guardOptions = getAllAuthGuardOptions(route);
|
|
58
|
+
*
|
|
59
|
+
* for (const option of guardOptions) {
|
|
60
|
+
* const conditionMet = checkAuthCondition(option.condition, authState);
|
|
61
|
+
* if (option.state !== conditionMet) {
|
|
62
|
+
* router.navigateByUrl(option.redirect);
|
|
63
|
+
* return false;
|
|
64
|
+
* }
|
|
65
|
+
* }
|
|
66
|
+
*
|
|
67
|
+
* return true;
|
|
68
|
+
* };
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* // Route hierarchy with inherited guards
|
|
74
|
+
* const routes: Routes = [
|
|
75
|
+
* {
|
|
76
|
+
* path: 'app',
|
|
77
|
+
* data: { [AUTH_GUARD_OPTIONS_KEY]: [
|
|
78
|
+
* { condition: AuthGuardCondition.SIGNED_IN, state: true, redirect: '/login' }
|
|
79
|
+
* ]},
|
|
80
|
+
* children: [
|
|
81
|
+
* {
|
|
82
|
+
* path: 'profile',
|
|
83
|
+
* component: ProfileComponent,
|
|
84
|
+
* data: { [AUTH_GUARD_OPTIONS_KEY]: [
|
|
85
|
+
* { condition: AuthGuardCondition.HAS_TOKEN, state: true, redirect: '/expired' }
|
|
86
|
+
* ]}
|
|
87
|
+
* }
|
|
88
|
+
* ]
|
|
89
|
+
* }
|
|
90
|
+
* ];
|
|
91
|
+
*
|
|
92
|
+
* // When accessing /app/profile, both parent and child guards apply
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* @see {@link AuthGuardOption} Interface defining the structure of guard options
|
|
96
|
+
* @see {@link AUTH_GUARD_OPTIONS_KEY} Constant for the route data key
|
|
97
|
+
* @see {@link authGuard} Function that uses this utility to process guard options
|
|
98
|
+
* @see {@link ActivatedRouteSnapshot} Angular router interface for route snapshots
|
|
99
|
+
*/
|
|
100
|
+
export declare const getAllAuthGuardOptions: (currentRoute: ActivatedRouteSnapshot) => AuthGuardOption[];
|