Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 16 additions & 25 deletions backend/typescript/rest/authRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,16 @@
/* Returns access token and user info in response body and sets refreshToken as an httpOnly cookie */
authRouter.post("/login", loginRequestValidator, async (req, res) => {
try {
const authDTO = req.body.idToken
? // OAuth
await authService.generateTokenOAuth(req.body.idToken)
: await authService.generateToken(req.body.email, req.body.password);
const authDTO = req.body.idToken;
await authService.generateToken(req.body.email, req.body.password);

const { refreshToken, ...rest } = authDTO;

res
.cookie("refreshToken", refreshToken, cookieOptions)
.status(200)
.json(rest);
} catch (error: unknown) {
} catch (error) {
res.status(500).json({ error: getErrorMessage(error) });
}
});
Expand All @@ -57,29 +55,22 @@
async (req, res) => {
try {
if (isAuthorizedByEmail(req.body.email)) {
const user = await userService.getUserByEmail(req.body.email);
const userDTO = await userService.getUserByEmail(req.body.email);
const rest = { ...{ accessToken: req.body.accessToken }, ...userDTO };

const activatedUser = user;
activatedUser.status = UserStatus.ACTIVE;
await userService.updateUserById(user.id, activatedUser);

const rest = {
...{ accessToken: req.body.accessToken },
...activatedUser,
};
res
.cookie("refreshToken", req.body.refreshToken, cookieOptions)
.status(200)
.json(rest);
}
} catch (error: unknown) {
} catch (error) {
if (error instanceof NotFoundError) {
res.status(404).send(getErrorMessage(error));
} else {
res.status(500).json({ error: getErrorMessage(error) });
}
}
},
}

Check failure on line 73 in backend/typescript/rest/authRoutes.ts

View workflow job for this annotation

GitHub Actions / run-lint

Insert `,`
);

/* Returns access token in response body and sets refreshToken as an httpOnly cookie */
Expand All @@ -91,7 +82,7 @@
.cookie("refreshToken", token.refreshToken, cookieOptions)
.status(200)
.json({ accessToken: token.accessToken });
} catch (error: unknown) {
} catch (error) {
res.status(500).json({ error: getErrorMessage(error) });
}
});
Expand All @@ -104,10 +95,10 @@
try {
await authService.revokeTokens(req.params.userId);
res.status(204).send();
} catch (error: unknown) {
} catch (error) {
res.status(500).json({ error: getErrorMessage(error) });
}
},
}

Check failure on line 101 in backend/typescript/rest/authRoutes.ts

View workflow job for this annotation

GitHub Actions / run-lint

Insert `,`
);

/* Emails a password reset link to the user with the specified email */
Expand All @@ -118,10 +109,10 @@
try {
await authService.resetPassword(req.params.email);
res.status(204).send();
} catch (error: unknown) {
} catch (error) {
res.status(500).json({ error: getErrorMessage(error) });
}
},
}

Check failure on line 115 in backend/typescript/rest/authRoutes.ts

View workflow job for this annotation

GitHub Actions / run-lint

Insert `,`
);

// updates user password and updates status
Expand All @@ -132,7 +123,7 @@
try {
const responseSuccess = await authService.setPassword(
req.params.email,
req.body.newPassword,
req.body.newPassword

Check failure on line 126 in backend/typescript/rest/authRoutes.ts

View workflow job for this annotation

GitHub Actions / run-lint

Insert `,`
);
if (responseSuccess.success) {
const user = await userService.getUserByEmail(req.params.email);
Expand All @@ -149,15 +140,15 @@
} catch (error) {
res.status(500).json({ error: getErrorMessage(error) });
}
},
}

Check failure on line 143 in backend/typescript/rest/authRoutes.ts

View workflow job for this annotation

GitHub Actions / run-lint

Insert `,`
);

/* Invite a user */
authRouter.post("/invite-user", inviteUserDtoValidator, async (req, res) => {
try {
if (
!isAuthorizedByRole(
new Set([Role.ADMINISTRATOR, Role.ANIMAL_BEHAVIOURIST]),
new Set([Role.ADMINISTRATOR, Role.ANIMAL_BEHAVIOURIST])

Check failure on line 151 in backend/typescript/rest/authRoutes.ts

View workflow job for this annotation

GitHub Actions / run-lint

Insert `,`
)
) {
res
Expand All @@ -184,7 +175,7 @@
await userService.updateUserById(user.id, invitedUser);

res.status(204).send();
} catch (error: unknown) {
} catch (error) {
if (error instanceof NotFoundError) {
res.status(404).send(getErrorMessage(error));
} else {
Expand Down
34 changes: 0 additions & 34 deletions backend/typescript/services/implementations/authService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,40 +38,6 @@
}
}

/* eslint-disable class-methods-use-this */
async generateTokenOAuth(idToken: string): Promise<AuthDTO> {
try {
const googleUser = await FirebaseRestClient.signInWithGoogleOAuth(
idToken,
);
// googleUser.idToken refers to the Firebase Auth access token for the user
const token = {
accessToken: googleUser.idToken,
refreshToken: googleUser.refreshToken,
};
// If user already has a login with this email, just return the token
try {
// Note: an error message will be logged from UserService if this lookup fails.
// You may want to silence the logger for this special OAuth user lookup case
const user = await this.userService.getUserByEmail(googleUser.email);
return { ...token, ...user };
/* eslint-disable-next-line no-empty */
} catch (error) {}

const user = await this.userService.createUser({
firstName: googleUser.firstName,
lastName: googleUser.lastName,
email: googleUser.email,
role: Role.STAFF,
});

return { ...token, ...user };
} catch (error) {
Logger.error(`Failed to generate token for user with OAuth ID token`);
throw error;
}
}

async revokeTokens(userId: string): Promise<void> {
try {
const authId = await this.userService.getAuthIdById(userId);
Expand Down Expand Up @@ -298,7 +264,7 @@
password: newPassword,
});
return { success: true } as ResponseSuccessDTO;
} catch (error: any) {

Check warning on line 267 in backend/typescript/services/implementations/authService.ts

View workflow job for this annotation

GitHub Actions / run-lint

Unexpected any. Specify a different type
Logger.error(`Failed to update password. Error: ${error}`);
if (error.code === "auth/invalid-password") {
errorMessage =
Expand Down
9 changes: 0 additions & 9 deletions backend/typescript/services/interfaces/authService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,6 @@ interface IAuthService {
*/
generateToken(email: string, password: string): Promise<AuthDTO>;

/**
* Generate a short-lived JWT access token and a long-lived refresh token
* when supplied OAuth ID token
* @param idToken user's ID token
* @returns AuthDTO object containing the access token, refresh token, and user info
* @throws Error if token generation fails
*/
generateTokenOAuth(idToken: string): Promise<AuthDTO>;

/**
* Revoke all refresh tokens of a user
* @param userId userId of user whose refresh tokens are to be revoked
Expand Down
61 changes: 0 additions & 61 deletions backend/typescript/utilities/firebaseRestClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
"https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword";
const FIREBASE_REFRESH_TOKEN_URL =
"https://securetoken.googleapis.com/v1/token";
const FIREBASE_OAUTH_SIGN_IN_URL =
"https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp";

type PasswordSignInResponse = {
idToken: string;
Expand All @@ -21,27 +19,7 @@
registered: boolean;
};

type OAuthSignInResponse = {
federatedId: string;
providerId: string;
localId: string;
emailVerified: boolean;
email: string;
oauthIdToken: string;
oauthAccessToken: string;
oauthTokenSecret: string;
rawUserInfo: string;
firstName: string;
lastName: string;
fullName: string;
displayName: string;
photoUrl: string;
idToken: string;
refreshToken: string;
expiresIn: string;
needConfirmation: boolean;
};

Check failure on line 22 in backend/typescript/utilities/firebaseRestClient.ts

View workflow job for this annotation

GitHub Actions / run-lint

Delete `⏎`
type RefreshTokenResponse = {
expires_in: string;
token_type: string;
Expand Down Expand Up @@ -103,45 +81,6 @@
};
},

// Docs: https://firebase.google.com/docs/reference/rest/auth/#section-sign-in-with-oauth-credential
signInWithGoogleOAuth: async (
idToken: string,
): Promise<OAuthSignInResponse> => {
const response: Response = await fetch(
`${FIREBASE_OAUTH_SIGN_IN_URL}?key=${process.env.FIREBASE_WEB_API_KEY}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
postBody: `id_token=${idToken}&providerId=google.com`,
requestUri: process.env.FIREBASE_REQUEST_URI,
returnIdpCredential: true,
returnSecureToken: true,
}),
},
);

const responseJson:
| OAuthSignInResponse
| RequestError = await response.json();

if (!response.ok) {
const errorMessage = [
"Failed to sign-in via Firebase REST API with OAuth, status code =",
`${response.status},`,
"error message =",
(responseJson as RequestError).error.message,
];
Logger.error(errorMessage.join(" "));

throw new Error("Failed to sign-in via Firebase REST API");
}

return responseJson as OAuthSignInResponse;
},

// Docs: https://firebase.google.com/docs/reference/rest/auth/#section-refresh-token
refreshToken: async (refreshToken: string): Promise<Token> => {
const response: Response = await fetch(
Expand Down
Loading
Loading