From 337e6aee9775b1ef2e63e6a288fa806465c24286 Mon Sep 17 00:00:00 2001 From: tylercchase Date: Tue, 9 Dec 2025 15:05:26 -0500 Subject: [PATCH 01/11] feat(wip): add logic for grabbing user data on load from service --- src/app/app.component.ts | 11 +- .../header-buttons.component.ts | 8 +- src/app/services/auth.service.ts | 139 ++++++++++-------- src/app/services/user-data.service.ts | 20 ++- 4 files changed, 107 insertions(+), 71 deletions(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 58b587072..bd617cd3f 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -361,10 +361,13 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit { ), ); - const user = this.authService.getUser(); - if (user.id) { - this.store$.dispatch(new userStore.Login(user)); - } + this.subs.add( + this.authService.getUser().subscribe((user) => { + if (user.id) { + this.store$.dispatch(new userStore.Login(user)); + } + }), + ); this.subs.add( this.actions$ diff --git a/src/app/components/header/header-buttons/header-buttons.component.ts b/src/app/components/header/header-buttons/header-buttons.component.ts index 06598938e..54e26bd09 100644 --- a/src/app/components/header/header-buttons/header-buttons.component.ts +++ b/src/app/components/header/header-buttons/header-buttons.component.ts @@ -18,6 +18,7 @@ import { AsfApiService, EnvironmentService, ScreenSizeService, + UserDataService, } from '@services'; import { CMRProduct, @@ -74,6 +75,7 @@ declare global { }) export class HeaderButtonsComponent implements OnInit, OnDestroy { authService = inject(AuthService); + userData = inject(UserDataService); env = inject(EnvironmentService); private http = inject(HttpClient); asfApiService = inject(AsfApiService); @@ -108,9 +110,9 @@ export class HeaderButtonsComponent implements OnInit, OnDestroy { ngOnInit() { this.subs.add( - this.store$ - .select(userStore.getUserAuth) - .subscribe((user) => (this.userAuth = user)), + this.store$.select(userStore.getUserAuth).subscribe((user) => { + this.userAuth = user; + }), ); this.subs.add( diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts index 38a8e7def..e5df99fb9 100644 --- a/src/app/services/auth.service.ts +++ b/src/app/services/auth.service.ts @@ -1,5 +1,8 @@ import { Injectable, inject } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; +import { + HttpClient, + // HttpHeaders +} from '@angular/common/http'; import { interval, Subject, Observable, of } from 'rxjs'; import { map, takeUntil, take, filter, catchError } from 'rxjs/operators'; @@ -7,7 +10,7 @@ import { Store } from '@ngrx/store'; import { AppState } from '@store'; import { EnvironmentService } from './environment.service'; -import jwt_decode from 'jwt-decode'; +// import jwt_decode from 'jwt-decode'; import * as userStore from '@store/user'; import * as models from '@models'; @@ -27,11 +30,12 @@ export class AuthService { if (typeof BroadcastChannel !== 'undefined') { this.bc = new BroadcastChannel('asf-vertex'); this.bc.onmessage = (_event: MessageEvent) => { - const user = this.getUser(); + const user = this.existingUserInfo; if (!user.id) { this.store$.dispatch(new userStore.Logout()); } else { - this.store$.dispatch(new userStore.Login(user)); + // TODO: convert to promise then dispatch + this.store$.dispatch(new userStore.Login(this.existingUserInfo)); } }; } @@ -65,7 +69,6 @@ export class AuthService { ); const loginWindowClosed = new Subject(); - return interval(500).pipe( takeUntil(loginWindowClosed), map((_) => { @@ -78,7 +81,6 @@ export class AuthService { try { if (loginWindow.location.host === window.location.host) { loginWindow.close(); - user = this.getUser(); this.bc.postMessage({ event: 'login', }); @@ -112,70 +114,91 @@ export class AuthService { this.bc.postMessage({ event: 'logout', }); - return this.getUser(); + return this.existingUserInfo; }), catchError((_) => { this.notificationService.error('Trouble logging out', 'Error', { timeOut: 5000, }); - return of(this.getUser()); + return of(this.existingUserInfo); }), take(1), ); } - public getUser(): models.UserAuth { - const cookies = this.loadCookies(); - const token = cookies['asf-urs']; - - if (!token) { - return this.nullUser(); - } - try { - const user = jwt_decode(token); - - if (this.isExpired(user)) { - return this.nullUser(); - } - - setTimeout( - () => { - this.store$.dispatch(new userStore.Logout()); - this.notificationService.info( - 'Session Expired', - 'Please login again', - ); - }, - user.exp * 1000 - Date.now(), + private existingUserInfo: models.UserAuth = null; + public getUser(): Observable { + // const cookies = this.loadCookies(); + // const token = cookies['asf-urs']; + // if (!token) { + // return of(this.nullUser()); + // } + // try { + // const user = jwt_decode(token); + + // TODO: Replace the expired functionality with cookie based timestamps; + // if (this.isExpired(user)) { + // return of(this.nullUser()); + // } + return this.http + .get(`${this.env.currentEnv.user_data}/info/cookie`, { + withCredentials: true, + }) + .pipe( + map((x) => { + return { + id: x['urs-user-id'], + groups: x['urs-groups'], + token: x['token'], + }; + }), + map((final) => { + this.existingUserInfo = final; + return final; + }), ); - return this.makeUser(user['urs-user-id'], user['urs-groups'], token); - } catch (_error) { - return this.nullUser(); - } - } - - private makeUser( - id: string, - groups: models.URSGroup[], - token: string, - ): models.UserAuth { - return { id, token, groups }; + // setTimeout( + // () => { + // this.store$.dispatch(new userStore.Logout()); + // this.notificationService.info( + // 'Session Expired', + // 'Please login again', + // ); + // }, + // user.exp * 1000 - Date.now(), + // ); + + // return this.makeUser(user['urs-user-id'], user['urs-groups'], token); + // } catch (_error) { + // return of(this.nullUser()); + // } } - private nullUser(): models.UserAuth { - return { id: null, token: null, groups: [] }; - } - - private isExpired(userToken): boolean { - return Date.now() > userToken.exp * 1000; - } - - private loadCookies() { - return document.cookie - .split(';') - .map((s) => s.trim().split('=')) - .map(([name, val]) => ({ [name]: val })) - .reduce((allCookies, cookie) => ({ ...allCookies, ...cookie })); - } + // private makeUser( + // id: string, + // groups: models.URSGroup[], + // token: string, + // ): models.UserAuth { + // return { id, token, groups }; + // } + + // private makeAuthHeader(token: string): HttpHeaders { + // return new HttpHeaders().set('Authorization', `Bearer ${token}`); + // } + // private nullUser(): models.UserAuth { + // return { id: null, token: null, groups: [] }; + // } + + // private isExpired(userToken): boolean { + // return Date.now() > userToken.exp * 1000; + // } + + // private loadCookies() { + // return document.cookie + // .split(';') + // .map((s) => s.trim().split('=')) + // .map(([name, val]) => ({ [name]: val })) + // .reduce((allCookies, cookie) => ({ ...allCookies, ...cookie })); + // } } diff --git a/src/app/services/user-data.service.ts b/src/app/services/user-data.service.ts index 437ae40d7..cce716b9f 100644 --- a/src/app/services/user-data.service.ts +++ b/src/app/services/user-data.service.ts @@ -7,6 +7,15 @@ import { EnvironmentService } from './environment.service'; import { UserAuth } from '@models'; import { NotificationService } from './notification.service'; +interface UserInfo { + uid: string; + first_name: string; + last_name: string; + country: string; + email_address: string; + organization: string; +} + @Injectable({ providedIn: 'root', }) @@ -17,12 +26,11 @@ export class UserDataService { private baseUrl = this.getBaseUrlFrom(); - public getUserInfo$(userAuth: UserAuth): Observable { - const url = this.getUserInfoURL(this.baseUrl, userAuth.id); + public getUserInfo$(userAuth: UserAuth): Observable { + const url = this.getUserInfoURL(this.baseUrl); const headers = this.makeAuthHeader(userAuth.token); - return this.http - .get(url, { + .get(url, { headers, }) .pipe( @@ -116,7 +124,7 @@ export class UserDataService { private getBaseUrlFrom(): string { return this.env.currentEnv.user_data; } - public getUserInfoURL(baseUrl: string, userId: string): string { - return `${baseUrl}/vertex/${userId}/`; + public getUserInfoURL(baseUrl: string): string { + return `${baseUrl}/info/`; } } From 95edb34ba74b5ca50ecbe429646615790c293e63 Mon Sep 17 00:00:00 2001 From: tylercchase Date: Wed, 10 Dec 2025 15:03:50 -0500 Subject: [PATCH 02/11] feat: convert other user data endpoints to use cookie auth --- src/app/services/user-data.service.ts | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/app/services/user-data.service.ts b/src/app/services/user-data.service.ts index cce716b9f..63ee635a4 100644 --- a/src/app/services/user-data.service.ts +++ b/src/app/services/user-data.service.ts @@ -1,5 +1,5 @@ import { Injectable, inject } from '@angular/core'; -import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { HttpClient } from '@angular/common/http'; import { Observable, of } from 'rxjs'; import { catchError } from 'rxjs/operators'; @@ -26,12 +26,11 @@ export class UserDataService { private baseUrl = this.getBaseUrlFrom(); - public getUserInfo$(userAuth: UserAuth): Observable { + public getUserInfo$(_userAuth: UserAuth): Observable { const url = this.getUserInfoURL(this.baseUrl); - const headers = this.makeAuthHeader(userAuth.token); return this.http .get(url, { - headers, + withCredentials: true, }) .pipe( catchError((error) => { @@ -57,11 +56,10 @@ export class UserDataService { attribute: string, ): Observable { const url = this.makeEndpoint(this.baseUrl, userAuth.id, attribute); - const headers = this.makeAuthHeader(userAuth.token); return this.http .get(url, { - headers, + withCredentials: true, }) .pipe( catchError((error) => { @@ -88,11 +86,10 @@ export class UserDataService { value: T, ): Observable { const url = this.makeEndpoint(this.baseUrl, userAuth.id, attribute); - const headers = this.makeAuthHeader(userAuth.token); return this.http .post(url, value, { - headers, + withCredentials: true, }) .pipe( catchError((_) => { @@ -117,10 +114,6 @@ export class UserDataService { return `${baseUrl}/vertex/${userId}/${attributeName}`; } - private makeAuthHeader(token: string): HttpHeaders { - return new HttpHeaders().set('Authorization', `Bearer ${token}`); - } - private getBaseUrlFrom(): string { return this.env.currentEnv.user_data; } From 724ad203d248b2c915cf8a9bb307bccdaff1e06b Mon Sep 17 00:00:00 2001 From: tcchase Date: Fri, 12 Dec 2025 15:13:44 -0500 Subject: [PATCH 03/11] chore: update appdata-test url --- src/app/services/envs/env-devel.ts | 2 +- src/app/services/envs/env-prod.ts | 2 +- src/app/services/envs/env-test.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/services/envs/env-devel.ts b/src/app/services/envs/env-devel.ts index d67a2e094..fe38a6043 100644 --- a/src/app/services/envs/env-devel.ts +++ b/src/app/services/envs/env-devel.ts @@ -16,7 +16,7 @@ export const env = { urs: 'https://urs.earthdata.nasa.gov', urs_client_id: 'BO_n7nTIlMljdvU6kRRB3g', banner: 'https://banners.asf.alaska.edu', - user_data: 'https://cgdjuem3wc.execute-api.us-east-1.amazonaws.com/prod/', + user_data: 'https://appdata-test.asf.alaska.edu', unzip: 'https://unzip.asf.alaska.edu', bulk_download: 'https://bulk-download.asf.alaska.edu', }, diff --git a/src/app/services/envs/env-prod.ts b/src/app/services/envs/env-prod.ts index 870283201..62afa887e 100644 --- a/src/app/services/envs/env-prod.ts +++ b/src/app/services/envs/env-prod.ts @@ -16,7 +16,7 @@ export const env = { urs: 'https://urs.earthdata.nasa.gov', urs_client_id: 'BO_n7nTIlMljdvU6kRRB3g', banner: 'https://banners.asf.alaska.edu', - user_data: 'https://cgdjuem3wc.execute-api.us-east-1.amazonaws.com/prod/', + user_data: 'https://appdata-test.asf.alaska.edu', unzip: 'https://unzip.asf.alaska.edu', bulk_download: 'https://bulk-download.asf.alaska.edu', }, diff --git a/src/app/services/envs/env-test.ts b/src/app/services/envs/env-test.ts index d67a2e094..fe38a6043 100644 --- a/src/app/services/envs/env-test.ts +++ b/src/app/services/envs/env-test.ts @@ -16,7 +16,7 @@ export const env = { urs: 'https://urs.earthdata.nasa.gov', urs_client_id: 'BO_n7nTIlMljdvU6kRRB3g', banner: 'https://banners.asf.alaska.edu', - user_data: 'https://cgdjuem3wc.execute-api.us-east-1.amazonaws.com/prod/', + user_data: 'https://appdata-test.asf.alaska.edu', unzip: 'https://unzip.asf.alaska.edu', bulk_download: 'https://bulk-download.asf.alaska.edu', }, From fba34cf903ad705bdffcfd965a9a4a3f99ba1665 Mon Sep 17 00:00:00 2001 From: tylercchase Date: Tue, 16 Dec 2025 12:30:18 -0500 Subject: [PATCH 04/11] feat: login button functionality works --- src/app/app.component.ts | 2 +- src/app/models/user.model.ts | 1 + src/app/services/auth.service.ts | 122 ++++++++++++----------------- src/app/store/user/user.reducer.ts | 2 + 4 files changed, 53 insertions(+), 74 deletions(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index bd617cd3f..303b1e9ae 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -363,7 +363,7 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit { this.subs.add( this.authService.getUser().subscribe((user) => { - if (user.id) { + if (user?.id) { this.store$.dispatch(new userStore.Login(user)); } }), diff --git a/src/app/models/user.model.ts b/src/app/models/user.model.ts index 193ef43e8..303bd1e7d 100644 --- a/src/app/models/user.model.ts +++ b/src/app/models/user.model.ts @@ -4,6 +4,7 @@ export interface UserAuth { id: string | null; token: string | null; groups: URSGroup[]; + exp: number; } export interface UserProfile { diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts index e5df99fb9..9754bb9eb 100644 --- a/src/app/services/auth.service.ts +++ b/src/app/services/auth.service.ts @@ -5,7 +5,14 @@ import { } from '@angular/common/http'; import { interval, Subject, Observable, of } from 'rxjs'; -import { map, takeUntil, take, filter, catchError } from 'rxjs/operators'; +import { + map, + takeUntil, + take, + filter, + catchError, + mergeMap, +} from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { AppState } from '@store'; @@ -24,19 +31,25 @@ export class AuthService { private http = inject(HttpClient); private notificationService = inject(NotificationService); private store$ = inject>(Store); + private existingUserInfo: models.UserAuth = null; private bc: BroadcastChannel; constructor() { if (typeof BroadcastChannel !== 'undefined') { this.bc = new BroadcastChannel('asf-vertex'); this.bc.onmessage = (_event: MessageEvent) => { - const user = this.existingUserInfo; - if (!user.id) { - this.store$.dispatch(new userStore.Logout()); - } else { - // TODO: convert to promise then dispatch - this.store$.dispatch(new userStore.Login(this.existingUserInfo)); - } + this.getUser() + .pipe( + take(1), + map((user) => { + if (!user.id) { + this.store$.dispatch(new userStore.Logout()); + } else { + this.store$.dispatch(new userStore.Login(user)); + } + }), + ) + .subscribe(); }; } } @@ -72,8 +85,6 @@ export class AuthService { return interval(500).pipe( takeUntil(loginWindowClosed), map((_) => { - let user = null; - if (loginWindow.closed) { loginWindowClosed.next(); } @@ -88,8 +99,6 @@ export class AuthService { } catch (_e) { // Do nothing } - - return user; }), catchError((_) => { this.notificationService.error('Trouble logging in', 'Error', { @@ -98,6 +107,9 @@ export class AuthService { loginWindowClosed.next(); return of(null); }), + mergeMap(() => { + return this.getUser(); + }), filter((user) => !!user), take(1), ); @@ -126,79 +138,43 @@ export class AuthService { ); } - private existingUserInfo: models.UserAuth = null; public getUser(): Observable { - // const cookies = this.loadCookies(); - // const token = cookies['asf-urs']; - // if (!token) { - // return of(this.nullUser()); - // } - // try { - // const user = jwt_decode(token); - - // TODO: Replace the expired functionality with cookie based timestamps; - // if (this.isExpired(user)) { - // return of(this.nullUser()); - // } return this.http .get(`${this.env.currentEnv.user_data}/info/cookie`, { withCredentials: true, }) .pipe( - map((x) => { - return { - id: x['urs-user-id'], - groups: x['urs-groups'], - token: x['token'], - }; + map((user) => { + return this.makeUser( + user['urs-user-id'], + user['urs-groups'], + user['token'], + user['exp'], + ); }), map((final) => { this.existingUserInfo = final; + setTimeout( + () => { + this.store$.dispatch(new userStore.Logout()); + this.notificationService.info( + 'Session Expired', + 'Please login again', + ); + }, + final.exp * 1000 - Date.now(), + ); return final; }), ); - - // setTimeout( - // () => { - // this.store$.dispatch(new userStore.Logout()); - // this.notificationService.info( - // 'Session Expired', - // 'Please login again', - // ); - // }, - // user.exp * 1000 - Date.now(), - // ); - - // return this.makeUser(user['urs-user-id'], user['urs-groups'], token); - // } catch (_error) { - // return of(this.nullUser()); - // } } - // private makeUser( - // id: string, - // groups: models.URSGroup[], - // token: string, - // ): models.UserAuth { - // return { id, token, groups }; - // } - - // private makeAuthHeader(token: string): HttpHeaders { - // return new HttpHeaders().set('Authorization', `Bearer ${token}`); - // } - // private nullUser(): models.UserAuth { - // return { id: null, token: null, groups: [] }; - // } - - // private isExpired(userToken): boolean { - // return Date.now() > userToken.exp * 1000; - // } - - // private loadCookies() { - // return document.cookie - // .split(';') - // .map((s) => s.trim().split('=')) - // .map(([name, val]) => ({ [name]: val })) - // .reduce((allCookies, cookie) => ({ ...allCookies, ...cookie })); - // } + private makeUser( + id: string, + groups: models.URSGroup[], + token: string, + exp: number, + ): models.UserAuth { + return { id, token, groups, exp }; + } } diff --git a/src/app/store/user/user.reducer.ts b/src/app/store/user/user.reducer.ts index c06dfe545..49d68b4ce 100644 --- a/src/app/store/user/user.reducer.ts +++ b/src/app/store/user/user.reducer.ts @@ -20,6 +20,7 @@ export const initState: UserState = { id: null, token: null, groups: [], + exp: null, }, profile: { defaultDataset: 'SENTINEL-1', @@ -62,6 +63,7 @@ export function userReducer(state = initState, action: UserActions): UserState { id: null, token: null, groups: [], + exp: null, }, }; } From 3f8fcb4fc9571e2c25c5103177b1214c3bc09069 Mon Sep 17 00:00:00 2001 From: tcchase Date: Tue, 6 Jan 2026 11:46:20 -0500 Subject: [PATCH 05/11] fix: grab user info after login window closes correctly --- src/app/services/auth.service.ts | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts index 9754bb9eb..7c70fd9aa 100644 --- a/src/app/services/auth.service.ts +++ b/src/app/services/auth.service.ts @@ -1,23 +1,19 @@ import { Injectable, inject } from '@angular/core'; -import { - HttpClient, - // HttpHeaders -} from '@angular/common/http'; +import { HttpClient } from '@angular/common/http'; import { interval, Subject, Observable, of } from 'rxjs'; import { map, takeUntil, take, - filter, catchError, - mergeMap, + filter, + switchMap, } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { AppState } from '@store'; import { EnvironmentService } from './environment.service'; -// import jwt_decode from 'jwt-decode'; import * as userStore from '@store/user'; import * as models from '@models'; @@ -84,21 +80,23 @@ export class AuthService { const loginWindowClosed = new Subject(); return interval(500).pipe( takeUntil(loginWindowClosed), - map((_) => { + switchMap((_) => { if (loginWindow.closed) { loginWindowClosed.next(); + return this.getUser(); } - try { if (loginWindow.location.host === window.location.host) { loginWindow.close(); this.bc.postMessage({ event: 'login', }); + return this.getUser(); } } catch (_e) { // Do nothing } + return of(null); }), catchError((_) => { this.notificationService.error('Trouble logging in', 'Error', { @@ -107,9 +105,6 @@ export class AuthService { loginWindowClosed.next(); return of(null); }), - mergeMap(() => { - return this.getUser(); - }), filter((user) => !!user), take(1), ); From f2ec388cf458ecbd33aa9c76fdef9203286bc49a Mon Sep 17 00:00:00 2001 From: tcchase Date: Tue, 6 Jan 2026 15:44:51 -0500 Subject: [PATCH 06/11] feat: use updated cumulus links --- src/app/services/auth.service.ts | 2 +- src/app/services/env.ts | 17 ++++++++++++++--- src/app/services/environment.service.ts | 2 +- src/app/services/envs/env-prod.ts | 4 ++-- src/app/services/envs/env-test.ts | 15 +++++++++++++-- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts index 7c70fd9aa..0869722e1 100644 --- a/src/app/services/auth.service.ts +++ b/src/app/services/auth.service.ts @@ -112,7 +112,7 @@ export class AuthService { public logout$(): Observable { return this.http - .get(`${this.authUrl}/loginservice/logout`, { + .get(`${this.authUrl}/logout`, { responseType: 'text', withCredentials: true, }) diff --git a/src/app/services/env.ts b/src/app/services/env.ts index d67a2e094..6d6a71f46 100644 --- a/src/app/services/env.ts +++ b/src/app/services/env.ts @@ -1,7 +1,7 @@ export const env = { prod: { api: 'https://api.daac.asf.alaska.edu', - auth: 'https://auth.asf.alaska.edu', + auth: 'https://cumulus.asf.alaska.edu', urs: 'https://urs.earthdata.nasa.gov', urs_client_id: 'BO_n7nTIlMljdvU6kRRB3g', banner: 'https://banners.asf.alaska.edu', @@ -12,11 +12,22 @@ export const env = { test: { api: 'https://api-test.asf.alaska.edu', api_maturity: 'prod', - auth: 'https://auth.asf.alaska.edu', + auth: 'https://cumulus.asf.alaska.edu', urs: 'https://urs.earthdata.nasa.gov', urs_client_id: 'BO_n7nTIlMljdvU6kRRB3g', banner: 'https://banners.asf.alaska.edu', - user_data: 'https://cgdjuem3wc.execute-api.us-east-1.amazonaws.com/prod/', + user_data: 'https://appdata-test.asf.alaska.edu', + unzip: 'https://unzip.asf.alaska.edu', + bulk_download: 'https://bulk-download.asf.alaska.edu', + }, + 'test UAT': { + api: 'https://api-test.asf.alaska.edu', + api_maturity: 'test', + auth: 'https://sentinel1-test.asf.alaska.edu', + urs: 'https://uat.urs.earthdata.nasa.gov', + urs_client_id: 'Qkd0Z9KbhG86qedkRC7nSA', + banner: 'https://banners.asf.alaska.edu', + user_data: 'https://appdata-test.asf.alaska.edu', unzip: 'https://unzip.asf.alaska.edu', bulk_download: 'https://bulk-download.asf.alaska.edu', }, diff --git a/src/app/services/environment.service.ts b/src/app/services/environment.service.ts index 7ad0f27fc..af18b5051 100644 --- a/src/app/services/environment.service.ts +++ b/src/app/services/environment.service.ts @@ -18,7 +18,7 @@ export interface Environment { api_maturity?: string; urs_client_id: string; unzip: string; - datapool: string; + datapool?: string; banner: string; user_data: string; bulk_download: string; diff --git a/src/app/services/envs/env-prod.ts b/src/app/services/envs/env-prod.ts index 62afa887e..5a74d6def 100644 --- a/src/app/services/envs/env-prod.ts +++ b/src/app/services/envs/env-prod.ts @@ -1,7 +1,7 @@ export const env = { prod: { api: 'https://api-prod-private.asf.alaska.edu', - auth: 'https://auth.asf.alaska.edu', + auth: 'https://cumulus.asf.alaska.edu', urs: 'https://urs.earthdata.nasa.gov', urs_client_id: 'BO_n7nTIlMljdvU6kRRB3g', banner: 'https://banners.asf.alaska.edu', @@ -12,7 +12,7 @@ export const env = { test: { api: 'https://api-test.asf.alaska.edu', api_maturity: 'test', - auth: 'https://auth.asf.alaska.edu', + auth: 'https://sentinel1-test.asf.alaska.edu', urs: 'https://urs.earthdata.nasa.gov', urs_client_id: 'BO_n7nTIlMljdvU6kRRB3g', banner: 'https://banners.asf.alaska.edu', diff --git a/src/app/services/envs/env-test.ts b/src/app/services/envs/env-test.ts index fe38a6043..d1d259c4f 100644 --- a/src/app/services/envs/env-test.ts +++ b/src/app/services/envs/env-test.ts @@ -1,7 +1,7 @@ export const env = { prod: { api: 'https://api.daac.asf.alaska.edu', - auth: 'https://auth.asf.alaska.edu', + auth: 'https://cumulus.asf.alaska.edu', urs: 'https://urs.earthdata.nasa.gov', urs_client_id: 'BO_n7nTIlMljdvU6kRRB3g', banner: 'https://banners.asf.alaska.edu', @@ -12,7 +12,7 @@ export const env = { test: { api: 'https://api-test.asf.alaska.edu', api_maturity: 'prod', - auth: 'https://auth.asf.alaska.edu', + auth: 'https://sentinel1-test.asf.alaska.edu', urs: 'https://urs.earthdata.nasa.gov', urs_client_id: 'BO_n7nTIlMljdvU6kRRB3g', banner: 'https://banners.asf.alaska.edu', @@ -20,5 +20,16 @@ export const env = { unzip: 'https://unzip.asf.alaska.edu', bulk_download: 'https://bulk-download.asf.alaska.edu', }, + 'test UAT': { + api: 'https://api-test.asf.alaska.edu', + api_maturity: 'test', + auth: 'https://sentinel1-test.asf.alaska.edu', + urs: 'https://uat.urs.earthdata.nasa.gov', + urs_client_id: 'Qkd0Z9KbhG86qedkRC7nSA', + banner: 'https://banners.asf.alaska.edu', + user_data: 'https://appdata-test.asf.alaska.edu', + unzip: 'https://unzip.asf.alaska.edu', + bulk_download: 'https://bulk-download.asf.alaska.edu', + }, defaultEnv: 'test', }; From b10094deb215688f4721c4937560af3e7a15c6ef Mon Sep 17 00:00:00 2001 From: tcchase Date: Tue, 6 Jan 2026 15:59:12 -0500 Subject: [PATCH 07/11] fix: regular test using wrong url for tea --- src/app/services/envs/env-prod.ts | 2 +- src/app/services/envs/env-test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/services/envs/env-prod.ts b/src/app/services/envs/env-prod.ts index 5a74d6def..159321756 100644 --- a/src/app/services/envs/env-prod.ts +++ b/src/app/services/envs/env-prod.ts @@ -12,7 +12,7 @@ export const env = { test: { api: 'https://api-test.asf.alaska.edu', api_maturity: 'test', - auth: 'https://sentinel1-test.asf.alaska.edu', + auth: 'https://cumulus.asf.alaska.edu', urs: 'https://urs.earthdata.nasa.gov', urs_client_id: 'BO_n7nTIlMljdvU6kRRB3g', banner: 'https://banners.asf.alaska.edu', diff --git a/src/app/services/envs/env-test.ts b/src/app/services/envs/env-test.ts index d1d259c4f..6d6a71f46 100644 --- a/src/app/services/envs/env-test.ts +++ b/src/app/services/envs/env-test.ts @@ -12,7 +12,7 @@ export const env = { test: { api: 'https://api-test.asf.alaska.edu', api_maturity: 'prod', - auth: 'https://sentinel1-test.asf.alaska.edu', + auth: 'https://cumulus.asf.alaska.edu', urs: 'https://urs.earthdata.nasa.gov', urs_client_id: 'BO_n7nTIlMljdvU6kRRB3g', banner: 'https://banners.asf.alaska.edu', From b629deb18084fa227d3a34fa943e1a21d5181ecc Mon Sep 17 00:00:00 2001 From: tcchase Date: Thu, 8 Jan 2026 11:48:30 -0500 Subject: [PATCH 08/11] chore: add some user info request guardrails --- src/app/services/auth.service.ts | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts index 0869722e1..a81eed902 100644 --- a/src/app/services/auth.service.ts +++ b/src/app/services/auth.service.ts @@ -9,6 +9,7 @@ import { catchError, filter, switchMap, + retry, } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { AppState } from '@store'; @@ -124,21 +125,26 @@ export class AuthService { return this.existingUserInfo; }), catchError((_) => { - this.notificationService.error('Trouble logging out', 'Error', { - timeOut: 5000, - }); + // For now this always throws a CORS error, but it does still logout successfully + // this.notificationService.error('Trouble logging out', 'Error', { + // timeOut: 5000, + // }); return of(this.existingUserInfo); }), take(1), ); } - public getUser(): Observable { + public getUser(): Observable { return this.http .get(`${this.env.currentEnv.user_data}/info/cookie`, { withCredentials: true, }) .pipe( + retry({ + count: 3, + delay: 100, + }), map((user) => { return this.makeUser( user['urs-user-id'], @@ -161,6 +167,11 @@ export class AuthService { ); return final; }), + catchError((_error) => { + console.error('Failed to get user info'); + return of(null); + }), + take(1), ); } From ed23ca83efb1019d5df9e07bebb4716f9271ce07 Mon Sep 17 00:00:00 2001 From: tylercchase Date: Tue, 20 Jan 2026 15:36:47 -0500 Subject: [PATCH 09/11] chore: check nullish user property --- src/app/app.component.ts | 2 +- .../header-buttons/preferences/preferences.component.html | 2 +- src/app/services/auth.service.ts | 2 +- src/app/services/user-data.service.ts | 4 ++-- src/app/store/user/user.effect.ts | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 303b1e9ae..be0a70745 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -303,7 +303,7 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit { this.subs.add( this.store$ .select(userStore.getUserAuth) - .pipe(filter((userAuth) => !!userAuth.token)) + .pipe(filter((userAuth) => !!userAuth?.token)) .subscribe((_) => this.store$.dispatch(new userStore.LoadProfile())), ); diff --git a/src/app/components/header/header-buttons/preferences/preferences.component.html b/src/app/components/header/header-buttons/preferences/preferences.component.html index e3193a416..c2967b398 100644 --- a/src/app/components/header/header-buttons/preferences/preferences.component.html +++ b/src/app/components/header/header-buttons/preferences/preferences.component.html @@ -1,6 +1,6 @@
- {{ 'PREFERENCES_FOR' | translate }} {{ userAuth.id }} + {{ 'PREFERENCES_FOR' | translate }} {{ userAuth?.id }}
diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts index a81eed902..4a04fa89d 100644 --- a/src/app/services/auth.service.ts +++ b/src/app/services/auth.service.ts @@ -39,7 +39,7 @@ export class AuthService { .pipe( take(1), map((user) => { - if (!user.id) { + if (!user?.id) { this.store$.dispatch(new userStore.Logout()); } else { this.store$.dispatch(new userStore.Login(user)); diff --git a/src/app/services/user-data.service.ts b/src/app/services/user-data.service.ts index 63ee635a4..117ade3aa 100644 --- a/src/app/services/user-data.service.ts +++ b/src/app/services/user-data.service.ts @@ -55,7 +55,7 @@ export class UserDataService { userAuth: UserAuth, attribute: string, ): Observable { - const url = this.makeEndpoint(this.baseUrl, userAuth.id, attribute); + const url = this.makeEndpoint(this.baseUrl, userAuth?.id, attribute); return this.http .get(url, { @@ -85,7 +85,7 @@ export class UserDataService { attribute: string, value: T, ): Observable { - const url = this.makeEndpoint(this.baseUrl, userAuth.id, attribute); + const url = this.makeEndpoint(this.baseUrl, userAuth?.id, attribute); return this.http .post(url, value, { diff --git a/src/app/store/user/user.effect.ts b/src/app/store/user/user.effect.ts index 531694f16..3e43ec988 100644 --- a/src/app/store/user/user.effect.ts +++ b/src/app/store/user/user.effect.ts @@ -147,7 +147,7 @@ export class UserEffects { this.store$.select(userReducer.getSearchHistory), ]), ), - filter(([_, [userAuth, _searches]]) => userAuth.id !== null), + filter(([_, [userAuth, _searches]]) => userAuth?.id !== null), switchMap(([_, [userAuth, searches]]) => this.userDataService.setAttribute$(userAuth, 'History', searches), ), From 4dc93922f4aa3caf8e44e67d2b929bda182a4c26 Mon Sep 17 00:00:00 2001 From: tylercchase Date: Tue, 20 Jan 2026 15:38:15 -0500 Subject: [PATCH 10/11] chore: update environment configs --- src/app/services/env.ts | 13 +------------ src/app/services/envs/env-prod.ts | 2 +- src/app/services/envs/env-test.ts | 13 +------------ 3 files changed, 3 insertions(+), 25 deletions(-) diff --git a/src/app/services/env.ts b/src/app/services/env.ts index 6d6a71f46..0993bb406 100644 --- a/src/app/services/env.ts +++ b/src/app/services/env.ts @@ -1,7 +1,7 @@ export const env = { prod: { api: 'https://api.daac.asf.alaska.edu', - auth: 'https://cumulus.asf.alaska.edu', + auth: 'https://auth.asf.alaska.edu', urs: 'https://urs.earthdata.nasa.gov', urs_client_id: 'BO_n7nTIlMljdvU6kRRB3g', banner: 'https://banners.asf.alaska.edu', @@ -20,16 +20,5 @@ export const env = { unzip: 'https://unzip.asf.alaska.edu', bulk_download: 'https://bulk-download.asf.alaska.edu', }, - 'test UAT': { - api: 'https://api-test.asf.alaska.edu', - api_maturity: 'test', - auth: 'https://sentinel1-test.asf.alaska.edu', - urs: 'https://uat.urs.earthdata.nasa.gov', - urs_client_id: 'Qkd0Z9KbhG86qedkRC7nSA', - banner: 'https://banners.asf.alaska.edu', - user_data: 'https://appdata-test.asf.alaska.edu', - unzip: 'https://unzip.asf.alaska.edu', - bulk_download: 'https://bulk-download.asf.alaska.edu', - }, defaultEnv: 'test', }; diff --git a/src/app/services/envs/env-prod.ts b/src/app/services/envs/env-prod.ts index 159321756..12773835e 100644 --- a/src/app/services/envs/env-prod.ts +++ b/src/app/services/envs/env-prod.ts @@ -1,7 +1,7 @@ export const env = { prod: { api: 'https://api-prod-private.asf.alaska.edu', - auth: 'https://cumulus.asf.alaska.edu', + auth: 'https://auth.asf.alaska.edu', urs: 'https://urs.earthdata.nasa.gov', urs_client_id: 'BO_n7nTIlMljdvU6kRRB3g', banner: 'https://banners.asf.alaska.edu', diff --git a/src/app/services/envs/env-test.ts b/src/app/services/envs/env-test.ts index 6d6a71f46..0993bb406 100644 --- a/src/app/services/envs/env-test.ts +++ b/src/app/services/envs/env-test.ts @@ -1,7 +1,7 @@ export const env = { prod: { api: 'https://api.daac.asf.alaska.edu', - auth: 'https://cumulus.asf.alaska.edu', + auth: 'https://auth.asf.alaska.edu', urs: 'https://urs.earthdata.nasa.gov', urs_client_id: 'BO_n7nTIlMljdvU6kRRB3g', banner: 'https://banners.asf.alaska.edu', @@ -20,16 +20,5 @@ export const env = { unzip: 'https://unzip.asf.alaska.edu', bulk_download: 'https://bulk-download.asf.alaska.edu', }, - 'test UAT': { - api: 'https://api-test.asf.alaska.edu', - api_maturity: 'test', - auth: 'https://sentinel1-test.asf.alaska.edu', - urs: 'https://uat.urs.earthdata.nasa.gov', - urs_client_id: 'Qkd0Z9KbhG86qedkRC7nSA', - banner: 'https://banners.asf.alaska.edu', - user_data: 'https://appdata-test.asf.alaska.edu', - unzip: 'https://unzip.asf.alaska.edu', - bulk_download: 'https://bulk-download.asf.alaska.edu', - }, defaultEnv: 'test', }; From 3035f1b74126ab44b4bb97dd4237c8ccbd9c0618 Mon Sep 17 00:00:00 2001 From: tcchase Date: Fri, 23 Jan 2026 10:43:02 -0500 Subject: [PATCH 11/11] fix: pass token to searchapi requests --- src/app/services/auth.service.ts | 2 +- src/app/store/user/user.reducer.ts | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts index 4a04fa89d..9c6b32f09 100644 --- a/src/app/services/auth.service.ts +++ b/src/app/services/auth.service.ts @@ -149,7 +149,7 @@ export class AuthService { return this.makeUser( user['urs-user-id'], user['urs-groups'], - user['token'], + user['urs-access-token'], user['exp'], ); }), diff --git a/src/app/store/user/user.reducer.ts b/src/app/store/user/user.reducer.ts index 49d68b4ce..ad536de61 100644 --- a/src/app/store/user/user.reducer.ts +++ b/src/app/store/user/user.reducer.ts @@ -2,7 +2,6 @@ import { createFeatureSelector, createSelector } from '@ngrx/store'; import { UserActionType, UserActions } from './user.action'; import * as models from '@models'; -import jwt_decode from 'jwt-decode'; /* State */ export interface UserState { @@ -265,11 +264,7 @@ export const getIsUserLoggedIn = createSelector( export const getUserEDLToken = createSelector( getUserState, (state: UserState) => { - if (state.auth.token) { - const decoded = jwt_decode(state.auth.token); - return decoded['urs-access-token'] ?? null; - } - return null; + return state.auth.token ?? null; }, );