Files
zitadel/console/src/app/services/interceptors/auth.interceptor.ts
T
Elio BischofandGitHub b475068140 feat(console): friendly quota exhausted screen (#5790)
* fix: remove access interceptor for console

* feat: show dialog on exhausted requests

* fix exhausted cookie handling

* fix quota exhausted screen

* read instance mgmt from environment.json

* fix interceptors

* don't check cookie on environment.json

* fix environment.json path

* exclude environment.json from cookie check

* remove cookie before loading env

* use UTC to delete the cookie

* delete cookie before fetching env

* simplify cookie handling

* lint

* review cleanup

* use exhausted property from env json

* fix bootstrapping

* lint

* always open mgmt link if present

* chore: fetch env json before ng serve

* wait for cookie to be removed

* fix typo

* don't wait for cookie to be set
2023-05-19 10:48:39 +00:00

75 lines
2.3 KiB
TypeScript

import { Injectable } from '@angular/core';
import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog';
import { Request, UnaryInterceptor, UnaryResponse } from 'grpc-web';
import { Subject } from 'rxjs';
import { debounceTime, filter, first, take } from 'rxjs/operators';
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
import { AuthenticationService } from '../authentication.service';
import { StorageService } from '../storage.service';
const authorizationKey = 'Authorization';
const bearerPrefix = 'Bearer';
const accessTokenStorageKey = 'access_token';
@Injectable({ providedIn: 'root' })
/**
* Set the authentication token
*/
export class AuthInterceptor<TReq = unknown, TResp = unknown> implements UnaryInterceptor<TReq, TResp> {
public triggerDialog: Subject<boolean> = new Subject();
constructor(
private authenticationService: AuthenticationService,
private storageService: StorageService,
private dialog: MatDialog,
) {
this.triggerDialog.pipe(debounceTime(1000)).subscribe(() => {
this.openDialog();
});
}
public async intercept(request: Request<TReq, TResp>, invoker: any): Promise<UnaryResponse<TReq, TResp>> {
await this.authenticationService.authenticationChanged
.pipe(
filter((authed) => !!authed),
first(),
)
.toPromise();
const metadata = request.getMetadata();
const accessToken = this.storageService.getItem(accessTokenStorageKey);
metadata[authorizationKey] = `${bearerPrefix} ${accessToken}`;
return invoker(request)
.then((response: any) => {
return response;
})
.catch(async (error: any) => {
if (error.code === 16) {
this.triggerDialog.next(true);
}
return Promise.reject(error);
});
}
private openDialog(): void {
const dialogRef = this.dialog.open(WarnDialogComponent, {
data: {
confirmKey: 'ACTIONS.LOGIN',
titleKey: 'ERRORS.TOKENINVALID.TITLE',
descriptionKey: 'ERRORS.TOKENINVALID.DESCRIPTION',
},
disableClose: true,
width: '400px',
});
dialogRef
.afterClosed()
.pipe(take(1))
.subscribe((resp) => {
if (resp) {
this.authenticationService.authenticate(undefined, true);
}
});
}
}