377 lines
8.7 KiB
Markdown
377 lines
8.7 KiB
Markdown
# How to Use Auth Service in Your Projects
|
|
|
|
Step-by-step guide for integrating the authentication service into Dexar, Novo Markets, FastCheck, and BackOffice.
|
|
|
|
---
|
|
|
|
## 🚀 Quick Start
|
|
|
|
### 1. Add Environment Configuration
|
|
|
|
In each project, add auth service URL to your environment files:
|
|
|
|
**`src/environments/environment.ts`** (Development):
|
|
```typescript
|
|
export const environment = {
|
|
production: false,
|
|
authServiceUrl: 'http://localhost:4300',
|
|
apiUrl: 'http://localhost:3000/api',
|
|
projectId: 'dexar' // Change per project: dexar/novo/fastcheck/backoffice
|
|
};
|
|
```
|
|
|
|
**`src/environments/environment.production.ts`**:
|
|
```typescript
|
|
export const environment = {
|
|
production: true,
|
|
authServiceUrl: 'https://auth.dx-projects.com',
|
|
apiUrl: 'https://api.dx-projects.com/api',
|
|
projectId: 'dexar'
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## 📁 Files to Create
|
|
|
|
### Step 1: Create Auth Interceptor
|
|
|
|
**File:** `src/app/interceptors/auth.interceptor.ts`
|
|
|
|
```typescript
|
|
import { HttpInterceptorFn } from '@angular/common/http';
|
|
import { inject } from '@angular/core';
|
|
import { catchError, throwError } from 'rxjs';
|
|
import { environment } from '../../environments/environment';
|
|
|
|
export const authInterceptor: HttpInterceptorFn = (req, next) => {
|
|
const token = localStorage.getItem('authToken');
|
|
|
|
// Add token to API requests
|
|
if (token && req.url.includes(environment.apiUrl)) {
|
|
req = req.clone({
|
|
setHeaders: { Authorization: `Bearer ${token}` }
|
|
});
|
|
}
|
|
|
|
return next(req).pipe(
|
|
catchError((error) => {
|
|
// Redirect to auth service on 401
|
|
if (error.status === 401) {
|
|
localStorage.removeItem('authToken');
|
|
const currentUrl = window.location.href;
|
|
window.location.href = `${environment.authServiceUrl}/login?project=${environment.projectId}&redirect=${encodeURIComponent(currentUrl)}`;
|
|
}
|
|
return throwError(() => error);
|
|
})
|
|
);
|
|
};
|
|
```
|
|
|
|
### Step 2: Create Auth Guard
|
|
|
|
**File:** `src/app/guards/auth.guard.ts`
|
|
|
|
```typescript
|
|
import { inject } from '@angular/core';
|
|
import { CanActivateFn } from '@angular/router';
|
|
import { environment } from '../../environments/environment';
|
|
|
|
export const authGuard: CanActivateFn = () => {
|
|
const token = localStorage.getItem('authToken');
|
|
|
|
if (token) {
|
|
return true;
|
|
}
|
|
|
|
// Redirect to auth service
|
|
const currentUrl = window.location.href;
|
|
window.location.href = `${environment.authServiceUrl}/login?project=${environment.projectId}&redirect=${encodeURIComponent(currentUrl)}`;
|
|
|
|
return false;
|
|
};
|
|
```
|
|
|
|
### Step 3: Update App Config
|
|
|
|
**File:** `src/app/app.config.ts`
|
|
|
|
```typescript
|
|
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
|
|
import { provideRouter } from '@angular/router';
|
|
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
|
import { routes } from './app.routes';
|
|
import { authInterceptor } from './interceptors/auth.interceptor';
|
|
|
|
export const appConfig: ApplicationConfig = {
|
|
providers: [
|
|
provideZoneChangeDetection({ eventCoalescing: true }),
|
|
provideRouter(routes),
|
|
provideHttpClient(withInterceptors([authInterceptor]))
|
|
]
|
|
};
|
|
```
|
|
|
|
### Step 4: Handle Auth Callback in App Component
|
|
|
|
**Update:** `src/app/app.ts` or `src/app/app.component.ts`
|
|
|
|
```typescript
|
|
import { Component, OnInit } from '@angular/core';
|
|
import { Router, RouterOutlet } from '@angular/router';
|
|
|
|
@Component({
|
|
selector: 'app-root',
|
|
imports: [RouterOutlet],
|
|
template: '<router-outlet />',
|
|
styleUrls: ['./app.scss']
|
|
})
|
|
export class App implements OnInit {
|
|
constructor(private router: Router) {}
|
|
|
|
ngOnInit(): void {
|
|
// Handle token from auth service redirect
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const token = urlParams.get('token');
|
|
|
|
if (token) {
|
|
localStorage.setItem('authToken', token);
|
|
// Clean URL
|
|
window.history.replaceState({}, document.title, window.location.pathname);
|
|
// Navigate to dashboard
|
|
this.router.navigate(['/dashboard']);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Step 5: Protect Routes
|
|
|
|
**Update:** `src/app/app.routes.ts`
|
|
|
|
```typescript
|
|
import { Routes } from '@angular/router';
|
|
import { authGuard } from './guards/auth.guard';
|
|
|
|
export const routes: Routes = [
|
|
{
|
|
path: 'dashboard',
|
|
loadComponent: () => import('./pages/dashboard/dashboard.component'),
|
|
canActivate: [authGuard] // ✅ Protected route
|
|
},
|
|
{
|
|
path: 'products',
|
|
loadComponent: () => import('./pages/products/products.component'),
|
|
canActivate: [authGuard] // ✅ Protected route
|
|
},
|
|
// ... more protected routes
|
|
];
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 Project-Specific Integration
|
|
|
|
### For Dexar (marketplaces):
|
|
```typescript
|
|
// src/environments/environment.ts
|
|
export const environment = {
|
|
production: false,
|
|
authServiceUrl: 'http://localhost:4300',
|
|
apiUrl: 'http://localhost:3000/api',
|
|
projectId: 'dexar'
|
|
};
|
|
```
|
|
|
|
### For Novo Markets:
|
|
```typescript
|
|
// src/environments/environment.novo.ts
|
|
export const environment = {
|
|
production: false,
|
|
authServiceUrl: 'http://localhost:4300',
|
|
apiUrl: 'http://localhost:3000/api',
|
|
projectId: 'novo',
|
|
brandName: 'Novo'
|
|
};
|
|
```
|
|
|
|
### For FastCheck:
|
|
```typescript
|
|
// FastCheck/src/environments/environment.ts
|
|
export const environment = {
|
|
production: false,
|
|
authServiceUrl: 'http://localhost:4300',
|
|
apiUrl: 'http://localhost:3000/api',
|
|
projectId: 'fastcheck'
|
|
};
|
|
```
|
|
|
|
### For BackOffice:
|
|
```typescript
|
|
// market-backOffice/src/environments/environment.ts
|
|
export const environment = {
|
|
production: false,
|
|
authServiceUrl: 'http://localhost:4300',
|
|
apiUrl: 'http://localhost:3000/api',
|
|
projectId: 'backoffice'
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## 🧪 Testing Integration
|
|
|
|
### Test Flow:
|
|
|
|
1. **Clear localStorage:**
|
|
```javascript
|
|
localStorage.removeItem('authToken');
|
|
```
|
|
|
|
2. **Navigate to protected route:**
|
|
```
|
|
http://localhost:4200/dashboard
|
|
```
|
|
|
|
3. **Should redirect to:**
|
|
```
|
|
http://localhost:4300/login?project=dexar&redirect=http://localhost:4200/dashboard
|
|
```
|
|
|
|
4. **After authentication, returns to:**
|
|
```
|
|
http://localhost:4200/dashboard?token=eyJ...
|
|
```
|
|
|
|
5. **Token stored, URL cleaned automatically**
|
|
|
|
---
|
|
|
|
## 🔧 Optional: Logout Functionality
|
|
|
|
### Create Auth Service
|
|
|
|
**File:** `src/app/services/auth.service.ts`
|
|
|
|
```typescript
|
|
import { Injectable, inject } from '@angular/core';
|
|
import { HttpClient } from '@angular/common/http';
|
|
import { environment } from '../../environments/environment';
|
|
|
|
@Injectable({ providedIn: 'root' })
|
|
export class AuthService {
|
|
private http = inject(HttpClient);
|
|
|
|
logout(): void {
|
|
const token = localStorage.getItem('authToken');
|
|
|
|
if (token) {
|
|
this.http.post(`${environment.apiUrl}/auth/logout`, {
|
|
deviceInfo: this.getDeviceInfo()
|
|
}).subscribe({
|
|
complete: () => this.clearAuth(),
|
|
error: () => this.clearAuth()
|
|
});
|
|
} else {
|
|
this.clearAuth();
|
|
}
|
|
}
|
|
|
|
private clearAuth(): void {
|
|
localStorage.removeItem('authToken');
|
|
window.location.href = `${environment.authServiceUrl}/login?project=${environment.projectId}`;
|
|
}
|
|
|
|
private getDeviceInfo() {
|
|
return {
|
|
deviceType: window.innerWidth < 768 ? 'mobile' : 'desktop',
|
|
deviceOS: null,
|
|
context: 'browser',
|
|
project: environment.projectId
|
|
};
|
|
}
|
|
}
|
|
```
|
|
|
|
### Use in Component:
|
|
|
|
```typescript
|
|
import { Component, inject } from '@angular/core';
|
|
import { AuthService } from './services/auth.service';
|
|
|
|
@Component({
|
|
selector: 'app-header',
|
|
template: `<button (click)="logout()">Logout</button>`
|
|
})
|
|
export class HeaderComponent {
|
|
private authService = inject(AuthService);
|
|
|
|
logout(): void {
|
|
this.authService.logout();
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 📦 Summary
|
|
|
|
**3 Files to Create:**
|
|
1. ✅ `interceptors/auth.interceptor.ts`
|
|
2. ✅ `guards/auth.guard.ts`
|
|
3. ✅ Update `app.config.ts`
|
|
|
|
**1 File to Modify:**
|
|
4. ✅ Update `app.ts` (handle token callback)
|
|
|
|
**1 Environment Update:**
|
|
5. ✅ Add `authServiceUrl` and `projectId`
|
|
|
|
**That's it!** Your project now uses centralized authentication! 🎉
|
|
|
|
---
|
|
|
|
## 🚀 Deployment
|
|
|
|
1. **Deploy Auth Service:**
|
|
```bash
|
|
cd auth-service
|
|
npm run build:prod
|
|
# Deploy to auth.dx-projects.com
|
|
```
|
|
|
|
2. **Update Production Environments:**
|
|
```typescript
|
|
authServiceUrl: 'https://auth.dx-projects.com'
|
|
```
|
|
|
|
3. **Configure CORS on Backend:**
|
|
- Allow `http://localhost:4300` (dev)
|
|
- Allow `https://auth.dx-projects.com` (prod)
|
|
- Allow all project domains
|
|
|
|
---
|
|
|
|
## ❓ Troubleshooting
|
|
|
|
### Infinite redirect loop?
|
|
- Ensure auth guard doesn't protect callback routes
|
|
- Check that token is being stored correctly
|
|
|
|
### Token not saved?
|
|
- Check browser console for errors
|
|
- Verify localStorage is available
|
|
- Check URL parameters parsing
|
|
|
|
### CORS errors?
|
|
- Backend must allow auth service domain
|
|
- Check CORS configuration
|
|
|
|
---
|
|
|
|
## 📚 More Documentation
|
|
|
|
- **Backend API:** See `BACKEND_API.md`
|
|
- **Project Setup:** See `README.md`
|
|
- **Support:** backend@dx-projects.com
|