Skip to content

Instantly share code, notes, and snippets.

@CodingBash
Last active January 31, 2026 02:37
Show Gist options
  • Select an option

  • Save CodingBash/459458ef3b477af162539ac896e056c3 to your computer and use it in GitHub Desktop.

Select an option

Save CodingBash/459458ef3b477af162539ac896e056c3 to your computer and use it in GitHub Desktop.
import { Injectable } from '@angular/core';
import { LocalStorageService } from 'ngx-localstorage';
import { WindowRef } from '../utilities/windowref.utils';
import { environment } from 'src/environments/environment';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { UserPrincipal } from 'src/app/models/user-principal';
import { LabGroup } from '../models/lab-group';
import { Study } from '../models/study';
@Injectable({
providedIn: 'root'
})
export class AuthenticationService {
private gatewayCheckAuthenticatedUrl: string = environment.gatewayCheckAuthenticatedUrl;
private gatewayGetUserUrl: string = environment.gatewayGetUserUrl;
private gatewayLoginUrl: string = environment.gatewayLoginUrl;
private gatewayLogoutUrl: string = environment.gatewayLogoutUrl;
constructor(
private winRef: WindowRef,
private http: HttpClient
) { }
public loginUserViaGateway(access_token: string) {
const headers = new HttpHeaders({
'Authorization': "Bearer " + access_token
})
return this.http.post<UserPrincipal>(this.gatewayLoginUrl, null, {headers: headers, withCredentials: true}).pipe(map(response => this.mapUserPrincipalResponse(response)));
}
public logoutUserViaGateway(){
return this.http.get<boolean>(this.gatewayLogoutUrl, {withCredentials: true});
}
public getCurrentUserViaGateway(): Observable<UserPrincipal> {
return this.http.get<UserPrincipal>(this.gatewayGetUserUrl, {withCredentials: true})
.pipe(
map(response => this.mapUserPrincipalResponse(response)));
}
public isAuthenticatedViaGateway(): Observable<boolean> {
return this.http.get<boolean>(this.gatewayCheckAuthenticatedUrl, {withCredentials: true});
}
/*
* DEPRECATED - not checking authentication via local storage, see isAuthenticatedViaGateway
*/
public isAuthenticatedViaLocalStorage(): boolean {
var token = this.winRef.nativeWindow.localStorage.getItem("CellxCognitoToken");
return token != null;
}
/*
* DEPRECATED - no need to store token since we have the session ID given by the CellX API gateway
*/
public setToken(token: string): void {
this.winRef.nativeWindow.localStorage.setItem("CellxCognitoToken", token);
}
private mapUserPrincipalResponse(response): UserPrincipal {
console.log(response);
let userPrincipal: UserPrincipal = new UserPrincipal();
userPrincipal.cognito_account_sub = response["cognito-user-sub"];
userPrincipal.cognito_account_email = response["cognito-user-email"];
userPrincipal.cognito_account_email_verified = response["cognito-user-email-verified"];
userPrincipal.cognito_account_name = response["cognito-user-name"];
userPrincipal.cognito_account_username = response["cognito-user-username"];
userPrincipal.cellx_account_account_id = response["cellx-user-account-id"];
userPrincipal.cellx_account_cognito_id = response["cellx-user-cognito-id"];
userPrincipal.cellx_account_roles = response["cellx-user-roles"].map(authority=>authority["authority"]);
// TODO: Provide LabGroup::studyNamesAnd DisplayNames (or just a list of studies)
userPrincipal.cellx_labgroups = response["cellx-groups"].map(labGroup => new LabGroup(labGroup["groupId"], labGroup["groupName"], null));
userPrincipal.cellx_accessible_studies = response["cellx-accessible-studies"].map(study => new Study(study["studyName"], study["studyInfo"], study["studyDisplayName"], study["embargoed"], study["createTime"], study["updateTime"]));
console.log(userPrincipal);
return userPrincipal;
}
}
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { AuthenticationService } from 'src/app/services/authentication.service';
import { environment } from 'src/environments/environment';
import { UserPrincipalService } from 'src/app/services/user-principal.service';
import { RootNavItemsEmitterService } from 'src/app/services/root-nav-items-emitter.service';
//import { AlertService, AuthenticationService } from '../_services';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
public cognitoLoginUrl: string = environment.cognitoLoginUrl;
public redirectToLoginMessage: boolean = null;
constructor(
private route: ActivatedRoute,
private router: Router,
private authenticationService: AuthenticationService,
private userPrincipalService: UserPrincipalService,
private rootNavItemsEmitterService: RootNavItemsEmitterService
) {}
ngOnInit() {
/*
* TODO: Can this be deletead
* Determine if we are redirecting to login or to home. This determines what message is displayed on the screen.
*/
if(this.route.snapshot.fragment){
this.redirectToLoginMessage = false;
} else {
this.redirectToLoginMessage = true;
}
this.authenticationService.isAuthenticatedViaGateway().subscribe(isAuthenticated => {
if(isAuthenticated){ // If the user is already authenticated
if(this.userPrincipalService.userPrincipalSource.getValue() == null){ // But there is no userPrincipal stored
this.authenticationService.getCurrentUserViaGateway().subscribe(userPrincipal => { // Refresh the userPrincipal by calling the user REST endpoint
this.userPrincipalService.setUserPrincipal(userPrincipal); // Set the retrieved user principal
this.rootNavItemsEmitterService.pingRootNavItemEvent();
this.router.navigate(['/home']); // userPrincipal now set, return client back to home page.
});
} else { // And there is a userPrincipal
this.router.navigate(['/home']); // Nothing to do - return them to the home page
}
// TODO: Optionally, readd a UserPrincipal to the UserPrincipalService
} else if (this.route.snapshot.fragment){ // If a hash fragment exists in the URL (redirected back from Cognito with access token in hash fragment)
/*
* Extract the URL fragment and get the id_token param (ignore the token type and expiration time)
* We ignore expiration since we will get new id_token whenever a back-end request fails. Though in the future, the expiration may be used to let Spring know how long to persist the id_token, and also to set an expiration for the token in local storage
*/
const fragment: string = this.route.snapshot.fragment; // Get fragment
const rawParams : string[] = fragment.split("&"); // Split params
let listParams : [string, string][] = rawParams.map(rawParam => {
let splittedParam : string[]= rawParam.split("=");
let param : [string, string] = [splittedParam[0], splittedParam[1]];
return param;
}); // Split params into key and value
let mapParams : Map<string, string> = new Map<string, string>(); // Initial map of params
listParams.forEach(param => mapParams.set(param[0], param[1])); // Set map values from the list of params
// Finally, get the access_token that was recieved from Cognito
const access_token : string = mapParams.get("access_token");
// TODO: This is minor, but if there is no access_token param, then we should redirect to cognitoLoginUrl - perhaps fragment is recieved from somewhere else, though unlikely
// Login using the access_token
this.authenticationService.loginUserViaGateway(access_token).subscribe(userPrincipal => {
// Set the user principal
// TODO: Need to be more efficient with how we set userPrincipal and when we call isAuthenticated endpoint
this.userPrincipalService.setUserPrincipal(userPrincipal);
// Refresh the root nav items.
this.rootNavItemsEmitterService.pingRootNavItemEvent();
this.router.navigate(['/home'])
});
} else { // If not authenticated or not redirected from Cognito
window.location.href = this.cognitoLoginUrl; // Redirect to the cognito login URL
}
})
}
}
import { Injectable } from '@angular/core';
import { UserPrincipal } from '../models/user-principal';
import { BehaviorSubject } from 'rxjs';
import { RootNavItemsEmitterService } from './root-nav-items-emitter.service';
@Injectable({
providedIn: 'root'
})
export class UserPrincipalService {
public userPrincipalSource = new BehaviorSubject<UserPrincipal>(null);
public userPrincipal$ = this.userPrincipalSource.asObservable();
constructor(private rootNavItemsEmitterService: RootNavItemsEmitterService) { }
public setUserPrincipal(userPrincipal: UserPrincipal) : void {
this.userPrincipalSource.next(userPrincipal);
this.rootNavItemsEmitterService.pingRootNavItemEvent();
}
}
import { LabGroup } from './lab-group';
import { Study } from './study';
/**
* Represents the Principal map from the CellX back-end
* TODO: Some of the attributes here are unnecessary - they should be removed here and from the original REST endpoints
*/
export class UserPrincipal {
/*
* Cognito account properties
*/
cognito_account_sub: string;
cognito_account_email: string;
cognito_account_email_verified: boolean;
cognito_account_name: string;
cognito_account_username: string;
/*
* CellX account properties
*/
cellx_account_account_id: string;
cellx_account_cognito_id: string;
cellx_account_roles: string[];
/*
* Cellx user access control properties
* TODO: This has yet to be implemented. First need to implement on back-end, then update the HttpClient mapper.
*/
cellx_labgroups: LabGroup[];
cellx_accessible_studies: Study[]
constructor(){}
/*
* TODO: For some odd reason, if the admin role ever changes (i.e. adding more admin types), then this method needs to be updated.
* TODO: Changing admin role indicators is a breaking change, so an implementation downtime would be required.
* TODO: Maybe consider retrieving role names via SQL directly (via REST endpoint) instead of hard code? Low priority.
*/
isAdmin() {
if(this.cellx_account_roles){
return this.cellx_account_roles.includes("ROLE_SITE_ADMIN"); // TODO: This needs to be in a constants file
} else {
return false;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment