💄 TOTP auth
This commit is contained in:
parent
c0daaf5820
commit
040f58fafe
@ -1,11 +1,21 @@
|
|||||||
<section class="flex flex-col md:flex-row h-screen items-center">
|
<section class="flex flex-col md:flex-row h-screen items-center">
|
||||||
<div
|
<div
|
||||||
class="relative bg-white dark:bg-surface-900 w-full md:max-w-md lg:max-w-full md:mx-auto md:w-1/2 xl:w-1/3 h-screen px-6 lg:px-16 xl:px-12 flex items-center justify-center">
|
class="relative bg-white dark:bg-surface-900 w-full md:max-w-md lg:max-w-full md:mx-auto md:w-1/2 xl:w-1/3 h-screen px-6 lg:px-16 xl:px-12 flex items-center justify-center">
|
||||||
<div class="max-w-xl w-full mx-auto h-100">
|
<div class="max-w-xl w-full mx-auto">
|
||||||
<div class="max-w-32 mx-auto">
|
<div class="max-w-32 mx-auto">
|
||||||
<img src="favicon.png" />
|
<img src="favicon.png" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="block lg:hidden w-full">
|
||||||
|
<div class="mt-4 text-center">
|
||||||
|
<div class="text-4xl font-bold leading-none">
|
||||||
|
Welcome to TRIP
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 text-lg tracking-tight leading-6 text-gray-400">Tourism and Recreational Interest Points.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="text-xl md:text-2xl font-bold leading-tight mt-10">
|
<div class="text-xl md:text-2xl font-bold leading-tight mt-10">
|
||||||
{{ isRegistering ? "Register" : "Sign in" }}
|
{{ isRegistering ? "Register" : "Sign in" }}
|
||||||
</div>
|
</div>
|
||||||
@ -18,6 +28,18 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@if (pendingOTP) {
|
||||||
|
<div pFocusTrap>
|
||||||
|
<p class="mt-8 text-center font-light text-gray-500">
|
||||||
|
Enter your TOTP code
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="mt-4 flex gap-2 flex-col items-center">
|
||||||
|
<p-inputotp [(ngModel)]="otp" [integerOnly]="true" size="large" [length]="6" />
|
||||||
|
<p-button text label="Confirm" (click)="verifyTOTP()" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
} @else {
|
||||||
@defer () {
|
@defer () {
|
||||||
@if (authParams?.oidc) {
|
@if (authParams?.oidc) {
|
||||||
<div class="mt-8 text-center">
|
<div class="mt-8 text-center">
|
||||||
@ -91,6 +113,7 @@
|
|||||||
<p-skeleton width="80px" height="2.5rem" />
|
<p-skeleton width="80px" height="2.5rem" />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="absolute bottom-4 left-1/2 transform -translate-x-1/2 text-sm flex flex-col items-center gap-2">
|
<div class="absolute bottom-4 left-1/2 transform -translate-x-1/2 text-sm flex flex-col items-center gap-2">
|
||||||
|
|||||||
@ -1,15 +1,16 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
import { FloatLabelModule } from 'primeng/floatlabel';
|
import { FloatLabelModule } from 'primeng/floatlabel';
|
||||||
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { InputTextModule } from 'primeng/inputtext';
|
import { InputTextModule } from 'primeng/inputtext';
|
||||||
import { ButtonModule } from 'primeng/button';
|
import { ButtonModule } from 'primeng/button';
|
||||||
import { FocusTrapModule } from 'primeng/focustrap';
|
import { FocusTrapModule } from 'primeng/focustrap';
|
||||||
import { AuthParams, AuthService } from '../../services/auth.service';
|
import { AuthParams, AuthService, TOTPRequired, Token } from '../../services/auth.service';
|
||||||
import { MessageModule } from 'primeng/message';
|
import { MessageModule } from 'primeng/message';
|
||||||
import { HttpErrorResponse } from '@angular/common/http';
|
import { HttpErrorResponse } from '@angular/common/http';
|
||||||
import { SkeletonModule } from 'primeng/skeleton';
|
import { SkeletonModule } from 'primeng/skeleton';
|
||||||
|
import { InputOtpModule } from 'primeng/inputotp';
|
||||||
import { take } from 'rxjs';
|
import { take } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -19,10 +20,12 @@ import { take } from 'rxjs';
|
|||||||
FloatLabelModule,
|
FloatLabelModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
ButtonModule,
|
ButtonModule,
|
||||||
|
FormsModule,
|
||||||
InputTextModule,
|
InputTextModule,
|
||||||
SkeletonModule,
|
SkeletonModule,
|
||||||
FocusTrapModule,
|
FocusTrapModule,
|
||||||
MessageModule,
|
MessageModule,
|
||||||
|
InputOtpModule,
|
||||||
],
|
],
|
||||||
templateUrl: './auth.component.html',
|
templateUrl: './auth.component.html',
|
||||||
styleUrl: './auth.component.scss',
|
styleUrl: './auth.component.scss',
|
||||||
@ -33,6 +36,9 @@ export class AuthComponent implements OnInit {
|
|||||||
authForm: FormGroup;
|
authForm: FormGroup;
|
||||||
error: string | undefined;
|
error: string | undefined;
|
||||||
isRegistering: boolean = false;
|
isRegistering: boolean = false;
|
||||||
|
pendingOTP: string = '';
|
||||||
|
otp: string = '';
|
||||||
|
username: string = '';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
@ -99,11 +105,12 @@ export class AuthComponent implements OnInit {
|
|||||||
|
|
||||||
this.authService.login(this.authForm.value).subscribe({
|
this.authService.login(this.authForm.value).subscribe({
|
||||||
next: (data) => {
|
next: (data) => {
|
||||||
if (!data.access_token) {
|
if ((data as Token)?.access_token) this.router.navigateByUrl(this.redirectURL);
|
||||||
this.error = 'Authentication failed';
|
|
||||||
return;
|
// If we're here, it means it's OTP time
|
||||||
}
|
this.username = (data as TOTPRequired).username;
|
||||||
this.router.navigateByUrl(this.redirectURL);
|
this.pendingOTP = (data as TOTPRequired).pending_code;
|
||||||
|
this.authForm.reset();
|
||||||
},
|
},
|
||||||
error: () => {
|
error: () => {
|
||||||
this.authForm.reset();
|
this.authForm.reset();
|
||||||
@ -111,6 +118,16 @@ export class AuthComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
verifyTOTP(): void {
|
||||||
|
this.error = '';
|
||||||
|
this.authService.verify_totp(this.username, this.pendingOTP, this.otp).subscribe({
|
||||||
|
next: (token) => {
|
||||||
|
if (token) this.router.navigateByUrl(this.redirectURL);
|
||||||
|
},
|
||||||
|
error: () => (this.otp = ''),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
getAuthParams() {
|
getAuthParams() {
|
||||||
this.authService
|
this.authService
|
||||||
.authParams()
|
.authParams()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user