Authentication with Amplify is very easy even though I struggled a little bit at the beginning.
Here's how I implemented my authentication. Let me know what you think.
- I created my auth auth.service.ts with all the possible operations:
`
import { Injectable } from '@angular/core';
import { CognitoUser } from 'amazon-cognito-identity-js';
import { Auth } from 'aws-amplify';
import { CognitoHostedUIIdentityProvider } from '@aws-amplify/auth';
@Injectable({
providedIn: 'root',
})
export class AuthService {
user: CognitoUser | undefined;
constructor() {}
async signIn({
email,
psw,
}: {
email: string;
psw: string;
}): Promise {
return Auth.signIn(email, psw);
}
async setNewPasswordFirstLogin({
psw,
}: {
psw: string;
}): Promise {
return Auth.completeNewPassword(this.user, psw);
}
async currentAuthenticatedUser(): Promise {
return Auth.currentAuthenticatedUser();
}
async signOut(): Promise {
return Auth.signOut();
}
async forgotPasswordSendEmail({
email,
}: {
email: string;
}): Promise {
return Auth.forgotPassword(email);
}
async forgotPasswordSetNewPsw({
email,
psw,
code,
}: {
email: string;
psw: string;
code: string;
}): Promise {
return Auth.forgotPasswordSubmit(email, code, psw);
}
setUser(user: CognitoUser) {
this.user = user;
}
async federatedSignIn({ type }: { type: string }) {
let provider: CognitoHostedUIIdentityProvider | undefined = undefined;
if (type === 'Google') provider = CognitoHostedUIIdentityProvider.Google;
if (type === 'Apple') provider = CognitoHostedUIIdentityProvider.Apple;
if (type === 'Facebook')
provider = CognitoHostedUIIdentityProvider.Facebook;
if (provider) {
return Auth.federatedSignIn({
provider: provider,
});
}
return;
}
}
`
- I created the jwt.interceptor.ts, this was the toughest part that I implemented.
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
} from '@angular/common/http';
import { Observable, from, switchMap, catchError, throwError } from 'rxjs';
import { environment } from 'src/environments/environment';
import { AuthService } from 'src/app/core/services/auth.service';
import { Auth } from 'aws-amplify';
import { CognitoUserSession } from 'amazon-cognito-identity-js';
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) {}
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
return from(Auth.currentSession()).pipe(
switchMap((auth: any) => {
// switchMap() is used instead of map().
const jwt: string = auth.idToken.jwtToken;
const authRequest = request.clone({
setHeaders: {
Authorization: `Bearer ${jwt}`,
},
});
return next.handle(authRequest);
}),
catchError((err) => {
if (err.status) {
return throwError(() => new Error(err));
}
})
);
}
}
- I implemented the error.interceptor.ts as well for the auto logout
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { Router } from '@angular/router';
import { AuthService } from '../services/auth.service';
import { LoaderService } from 'src/app/shared/services/loader.service';
/**
* This is used to logout the user, when the server responds with an unathorized status code.
* Especially when the session token expires.
* @export
* @class ErrorInterceptor
* @implements {HttpInterceptor}
*/
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
constructor(
private readonly router: Router,
private readonly authService: AuthService,
) {}
/**
* Interceptor intercepts the responses, and then process based on the received status code
* @param {HttpRequest<any>} request
* @param {HttpHandler} next
* @returns {Observable<HttpEvent<any>>}
* @memberof ErrorInterceptor
*/
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
catchError((err) => {
if (err.status === 401) {
// auto logout if 401 response returned from api
this.authService
.signOut()
.then(() => {
this.router.navigate(['/auth']);
})
.catch((err) => console.log(err));
}
// err.error is not null, if the ResponsenEntity contains an Exception
// err.error.message will give the custom message send from the server
const error = err.error.errorMessage || err.statusText;
return throwError(() => new Error(error));
})
);
}
}
I created a login component but it is a simple component that calls the service.
Let me know what you think about this implementation and if there's a better way to do this particular task.
Top comments (0)