Skip to content

Commit

Permalink
fix: Authentication only lasts one hour (#804)
Browse files Browse the repository at this point in the history
This also fixes an issue where the first auth token would be saved before a user id existed and would be saved to an invalid key.
  • Loading branch information
NigelBreslaw authored Mar 13, 2024
1 parent 6570cc3 commit 72957e8
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 49 deletions.
92 changes: 46 additions & 46 deletions native/app/authentication/AuthService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,16 @@ class AuthService {

const savedToken = await AsyncStorage.getItem(`${AuthService.currentUserID}${Store._refresh_token}`);
if (savedToken) {
const stringToken = parse(string(), savedToken);
const validatedToken = parse(authTokenSchema, JSON.parse(stringToken));
await AuthService.validateAndSetToken(validatedToken);
const p2 = performance.now();
console.log("init() took:", (p2 - p1).toFixed(4), "ms");
return true;
const tokenParse = safeParse(authTokenSchema, JSON.parse(savedToken));
if (tokenParse.success) {
await AuthService.validateAndSetToken(tokenParse.output);
const p2 = performance.now();
console.log("init() took:", (p2 - p1).toFixed(4), "ms");
return true;
}
}

// Logout as the saved token is invalid
AuthService.logoutCurrentUser();
return false;
} catch (e) {
console.error(e);
Expand Down Expand Up @@ -142,7 +144,9 @@ class AuthService {
const isValidRefresh = isValidRefreshToken(token);
if (!isValidRefresh) {
// Nothing can be done. The user needs to re-auth.
// TODO: Log out the user
console.error("Refresh token expired");
AuthService.logoutCurrentUser();
return reject(false);
}

Expand Down Expand Up @@ -187,9 +191,20 @@ class AuthService {
}

private static saveAndSetToken(token: AuthToken) {
const currentUserID = AuthService.currentUserID;
AsyncStorage.setItem(`${currentUserID}${Store._refresh_token}`, JSON.stringify(token));
AuthService.setAuthToken(token);
const parsedToken = safeParse(authTokenSchema, token);

if (parsedToken.success) {
const currentUserID = AuthService.currentUserID;
if (currentUserID === "") {
console.error("No currentUserID!!!");
} else {
console.info("currentUserID", currentUserID);
AsyncStorage.setItem(`${currentUserID}${Store._refresh_token}`, JSON.stringify(token));
AuthService.setAuthToken(token);
}
} else {
console.error("Failed to save token. Token is invalid");
}
}

// Method to subscribe to auth changes
Expand Down Expand Up @@ -301,24 +316,6 @@ class AuthService {

try {
const initialJSONToken = await getRefreshToken(code);
// const validatedToken = parse(authTokenSchema, initialJSONToken);
// const tokenJson = await getAccessToken(validatedToken);
// const validatedToken = safeParse(authTokenSchema, tokenJson)

// if (validatedToken.)

// .then((rawToken) => {
// try {
// const validatedToken = parse(authTokenSchema, rawToken);
// validatedToken.time_stamp = new Date().toISOString();
// return resolve(validatedToken);
// } catch (error) {
// console.error("went wrong here");
// return reject(error);
// }
// })

AuthService.saveAndSetToken(initialJSONToken);
AuthService.buildBungieAccount(initialJSONToken);
} catch (e) {
console.error("Failed to validate token", e);
Expand All @@ -333,30 +330,32 @@ class AuthService {

static async buildBungieAccount(authToken: AuthToken) {
if (authToken) {
try {
let rawLinkedProfiles = await getLinkedProfiles(authToken);
let linkedProfiles = parse(linkedProfilesSchema, rawLinkedProfiles);
let rawLinkedProfiles = await getLinkedProfiles(authToken);
let parsedProfiles = safeParse(linkedProfilesSchema, rawLinkedProfiles);

if (linkedProfiles.Response.profiles?.length === 0) {
rawLinkedProfiles = await getLinkedProfiles(authToken, true);
linkedProfiles = parse(linkedProfilesSchema, rawLinkedProfiles);
console.error("NOT IMPLEMENTED SPECIAL ACCOUNT SUPPORT: Contact [email protected]");
}
if (parsedProfiles.success && parsedProfiles.output.Response.profiles?.length === 0) {
rawLinkedProfiles = await getLinkedProfiles(authToken, true);
parsedProfiles = safeParse(linkedProfilesSchema, rawLinkedProfiles);
console.error("NOT IMPLEMENTED SPECIAL ACCOUNT SUPPORT: Contact [email protected]");
}

if (linkedProfiles.Response.profiles?.length === 0) {
console.error("No linked profiles");
return;
}
const bungieUser = getBungieUser(linkedProfiles);
if (parsedProfiles.success && parsedProfiles.output.Response.profiles?.length === 0) {
console.error("No linked profiles");
return;
}

if (parsedProfiles.success) {
const bungieUser = getBungieUser(parsedProfiles.output);
AuthService.setCurrentAccount(bungieUser);
await AsyncStorage.setItem(Store._bungie_user, JSON.stringify(bungieUser));
AuthService.saveAndSetToken(authToken);
AuthService.setLoggingIn(false);
} catch (e) {
// This is a catastrophic failure. The user is logged in but we can't get their linked profiles.
// It needs some kind of big alert and then a logout.
console.error("Error in buildBungieAccount", e);
AuthService.setLoggingIn(false);
return;
}
// This is a catastrophic failure. The user is logged in but we can't get their linked profiles.
// It needs some kind of big alert and then a logout.
console.error("Error in buildBungieAccount", parsedProfiles.output);
AuthService.setLoggingIn(false);
}
}

Expand All @@ -369,6 +368,7 @@ class AuthService {
await AsyncStorage.removeItem(`${AuthService.currentUserID}${Store._refresh_token}`);
AuthService.setAuthToken(null);
AuthService.setCurrentAccount(null);
AuthService.currentUserID = "";
} catch (e) {
throw new Error("Error removing current user from storage");
}
Expand Down
8 changes: 5 additions & 3 deletions native/app/authentication/Utilities.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { apiKey, clientID, clientSecret } from "@/constants/env.ts";
import * as base64 from "base-64";
import { isoTimestamp, number, object, optional, parse, string } from "valibot";
import { isoTimestamp, number, object, parse, string } from "valibot";
import type { Output } from "valibot";

export const authTokenSchema = object({
Expand All @@ -9,7 +9,7 @@ export const authTokenSchema = object({
membership_id: string(),
refresh_expires_in: number(),
refresh_token: string(),
time_stamp: optional(string([isoTimestamp()])),
time_stamp: string([isoTimestamp()]),
token_type: string(),
});

Expand Down Expand Up @@ -38,8 +38,10 @@ export function getRefreshToken(bungieCode: string): Promise<AuthToken> {
})
.then((rawToken) => {
try {
// Add the time_stamp or the validation will fail.
rawToken.time_stamp = new Date().toISOString();
const validatedToken = parse(authTokenSchema, rawToken);
validatedToken.time_stamp = new Date().toISOString();

return resolve(validatedToken);
} catch (error) {
console.error("went wrong here");
Expand Down

0 comments on commit 72957e8

Please sign in to comment.