Skip to content

Commit

Permalink
OAuth Impl
Browse files Browse the repository at this point in the history
  • Loading branch information
Alder Whiteford authored and Alder Whiteford committed Jun 18, 2024
1 parent 79e2a66 commit 08f5271
Show file tree
Hide file tree
Showing 25 changed files with 188 additions and 186 deletions.
2 changes: 1 addition & 1 deletion backend/entities/auth/base/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func (h *Handler) ProviderCallback(c *fiber.Ctx) error {
return err
}

return c.SendStatus(http.StatusOK)
return c.Status(http.StatusOK).JSON(user)
}

func (h *Handler) ProviderLogout(c *fiber.Ctx) error {
Expand Down
2 changes: 1 addition & 1 deletion backend/integrations/oauth/crypt/crypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func Encrypt(data string, passphrase string) (string, error) {
}

plaintext := []byte(data)
if len(plaintext) > 1028 {
if len(plaintext) > 4096 {
return "", fmt.Errorf("plaintext too long")
}

Expand Down
5 changes: 2 additions & 3 deletions backend/integrations/oauth/soth/sothic/sothic.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ func CompleteUserAuth(c *fiber.Ctx) (soth.User, error) {
}

gu, err := provider.FetchUser(sess)

return gu, err
}

Expand All @@ -227,6 +228,7 @@ func validateState(c *fiber.Ctx, sess soth.Session) error {
}

originalState := authURL.Query().Get("state")

if originalState != "" && (originalState != c.Query("state")) {
return errors.New("state token mismatch")
}
Expand Down Expand Up @@ -357,13 +359,10 @@ func updateSessionValue(session *session.Session, key, value string) error {
if err := gz.Close(); err != nil {
return err
}

encrypted, err := encrypter(b.String())
if err != nil {
return err
}

session.Set(key, encrypted)

return nil
}
8 changes: 4 additions & 4 deletions backend/middleware/auth/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ func (m *AuthMiddlewareHandler) UserAuthorizeById(c *fiber.Ctx) error {
return c.SendStatus(http.StatusUnauthorized)
}

user := models.UnmarshalUser(strUser)
user := *models.UnmarshalUser(strUser)

if user.Role == models.Super {
locals.SetUser(c, user)
locals.SetUser(c, &user)
return c.Next()
}

Expand All @@ -29,8 +29,8 @@ func (m *AuthMiddlewareHandler) UserAuthorizeById(c *fiber.Ctx) error {
return err
}

if idAsUUID == &user.ID {
locals.SetUser(c, user)
if *idAsUUID == user.ID {
locals.SetUser(c, &user)
return c.Next()
}

Expand Down
2 changes: 1 addition & 1 deletion backend/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func Init(db *gorm.DB, stores *store.Stores, integrations integrations.Integrati

applicationURL := settings.Application.ApplicationURL()

msftProvider := msft.New(settings.Microsft.Key, "myapp://auth/callback", settings.Microsft.Tenant)
msftProvider := msft.New(settings.Microsft.Key, fmt.Sprintf("%s/api/v1/auth/microsoftonline/callback", applicationURL), settings.Microsft.Tenant)
googProvider := goog.New(settings.Google.Key, settings.Google.Secret, fmt.Sprintf("%s/api/v1/auth/google/callback", applicationURL))

authMiddleware := authMiddleware.New(
Expand Down
2 changes: 1 addition & 1 deletion frontend/lib/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@generatesac/lib",
"version": "0.0.177",
"version": "0.0.179",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
58 changes: 13 additions & 45 deletions frontend/lib/src/api/authApi.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { LoginResponse, RefreshTokenRequestBody } from "../types/auth";
import {
EmailRequestBody,
VerifyEmailRequestBody,
VerifyPasswordResetTokenRequestBody,
} from "../types/verification";
import { baseApi } from "./base";
import { User, userSchema } from "../types";
import { LoginResponse, OAuthCallbackRequestQueryParams } from "../types/auth";
import { baseApi, handleQueryParams } from "./base";

const AUTH_API_BASE_URL = "/auth";
const PROVIDER = "microsoftonline";

export const authApi = baseApi.injectEndpoints({
endpoints: (builder) => ({
Expand All @@ -26,49 +23,20 @@ export const authApi = baseApi.injectEndpoints({
}
},
}),
logout: builder.mutation<void, void>({
logout: builder.query<void, void>({
query: () => ({
url: `${AUTH_API_BASE_URL}/logout`,
method: "POST",
}),
}),
refresh: builder.mutation<void, RefreshTokenRequestBody>({
query: (body) => ({
url: "refresh",
method: "POST",
body,
}),
}),
forgotPassword: builder.mutation<void, EmailRequestBody>({
query: (body) => ({
url: `${AUTH_API_BASE_URL}/forgot-password`,
method: "POST",
body,
}),
}),
verifyPasswordResetToken: builder.mutation<
void,
VerifyPasswordResetTokenRequestBody
>({
query: (body) => ({
url: `${AUTH_API_BASE_URL}/verify-reset`,
method: "POST",
body,
}),
}),
sendCode: builder.mutation<void, EmailRequestBody>({
query: (body) => ({
url: `${AUTH_API_BASE_URL}/send-code`,
method: "POST",
body,
method: "GET",
}),
}),
verifyEmail: builder.mutation<void, VerifyEmailRequestBody>({
query: (body) => ({
url: `${AUTH_API_BASE_URL}/verify-email`,
method: "POST",
body,
callback: builder.query<User, OAuthCallbackRequestQueryParams>({
query: (params) => ({
url: handleQueryParams(`${AUTH_API_BASE_URL}/${PROVIDER}/callback`, params),
method: "GET",
}),
transformResponse: (response) => {
return userSchema.parse(response);
}
}),
}),
});
2 changes: 1 addition & 1 deletion frontend/lib/src/api/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const baseApi = createApi({
// User slice existing must exist in all dependent apps:
const token = (getState() as { user: { accessToken: string } })?.user?.accessToken;
if (token) {
headers.set("Authorization", `Bearer ${token}`);
headers.set("_sac_session", token);
}
return headers;
},
Expand Down
11 changes: 0 additions & 11 deletions frontend/lib/src/api/userApi.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { z } from "zod";

import { UpdatePasswordRequestBody } from "../types/auth";
import { Club, clubSchema } from "../types/club";
import { PaginationQueryParams } from "../types/root";
import { Tag, tagSchema } from "../types/tag";
Expand Down Expand Up @@ -82,16 +81,6 @@ export const userApi = baseApi.injectEndpoints({
}),
invalidatesTags: (_result, _, id) => [{ type: "User", id }],
}),
updatePassword: builder.mutation<
void,
{ id: string; body: UpdatePasswordRequestBody }
>({
query: ({ id, body }) => ({
url: `${USER_API_BASE_URL}/${id}/password`,
method: "PATCH",
body,
}),
}),
userFollowing: builder.query<Club[], string>({
query: (id) => ({
url: `${USER_API_BASE_URL}/${id}/follower/`,
Expand Down
24 changes: 5 additions & 19 deletions frontend/lib/src/types/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,12 @@ export const loginResponseSchema = z.object({
sac_session: z.string(),
});

export const updatePasswordRequestBodySchema = z.object({
old_password: z.string().min(8),
new_password: z.string().min(8),
});

export const refreshTokenRequestBodySchema = z.object({
refresh_token: z.string(),
});

export const tokensSchema = z.object({
access_token: z.string(),
refresh_token: z.string(),
export const oauthCallbackRequestQueryParams = z.object({
code: z.string(),
session_state: z.string(),
state: z.string(),
});

// Types:
export type LoginResponse = z.infer<typeof loginResponseSchema>;
export type UpdatePasswordRequestBody = z.infer<
typeof updatePasswordRequestBodySchema
>;
export type RefreshTokenRequestBody = z.infer<
typeof refreshTokenRequestBodySchema
>;
export type Tokens = z.infer<typeof tokensSchema>;
export type OAuthCallbackRequestQueryParams = z.infer<typeof oauthCallbackRequestQueryParams>;
8 changes: 4 additions & 4 deletions frontend/lib/src/types/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { rootModelSchema } from "./root";
export const userRoleEnum = z.enum(["super", "student"]);

export const collegeEnum = z.enum([
"",
"CAMD",
"DMSB",
"KCCS",
Expand All @@ -18,6 +19,7 @@ export const collegeEnum = z.enum([
]);

export const majorEnum = z.enum([
"",
"africanaStudies",
"americanSignLanguage",
"americanSignLanguage-EnglishInterpreting",
Expand Down Expand Up @@ -120,7 +122,7 @@ export const majorEnum = z.enum([
"theatre",
]);

export const graduationCycleEnum = z.enum(["december", "may"]);
export const graduationCycleEnum = z.enum(["december", "may", ""]);

export const yearEnum = z.enum(["1", "2", "3", "4", "5"]);

Expand Down Expand Up @@ -155,16 +157,14 @@ export const createUserTagsRequestBodySchema = z.object({

const userSchemaIntermediate = z.object({
role: userRoleEnum,
first_name: z.string().min(1),
last_name: z.string().min(1),
name: z.string().min(1),
email: z.string().email(),
major0: majorEnum.optional(),
major1: majorEnum.optional(),
major2: majorEnum.optional(),
college: collegeEnum.optional(),
graduation_cycle: graduationCycleEnum.optional(),
graduation_year: z.number().optional(),
is_verified: z.boolean(),
});

export const userSchema = userSchemaIntermediate.merge(rootModelSchema);
Expand Down
2 changes: 1 addition & 1 deletion frontend/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/react-fontawesome": "^0.2.2",
"@fortawesome/react-native-fontawesome": "^0.3.2",
"@generatesac/lib": "0.0.177",
"@generatesac/lib": "0.0.179",
"@gorhom/bottom-sheet": "^4.6.3",
"@hookform/resolvers": "^3.4.2",
"@react-native-async-storage/async-storage": "^1.23.1",
Expand Down
7 changes: 4 additions & 3 deletions frontend/mobile/src/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export { ErrorBoundary } from 'expo-router';
SplashScreen.preventAutoHideAsync();

const InitalLayout = () => {
const { accessToken } = useAppSelector((state) => state.user);
const { accessToken, loggedIn } = useAppSelector((state) => state.user);
const {
eventPreviewRef,
eventId,
Expand All @@ -33,12 +33,13 @@ const InitalLayout = () => {
} = usePreview();

useEffect(() => {
if (accessToken) {
if (accessToken && loggedIn) {
router.push('/app/');
} else {
router.push('/auth/');
}
}, [accessToken]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [loggedIn]);

return (
<>
Expand Down
3 changes: 2 additions & 1 deletion frontend/mobile/src/app/app/(tabs)/calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import {
} from 'react-native-calendars-sac';
import { Theme } from 'react-native-calendars-sac/src/types';

import { eventApi } from '@generatesac/lib';

import { Box, Colors, createStyles } from '@/src/app/design-system';
import Calendar, {
DAY_EPOCH_TIME,
FetchNewEventsPropsUnion
} from '@/src/app/design-system/components/Calendar/Calendar';
import { EventSection } from '@/src/app/design-system/components/Calendar/DayTimeSection';
import { parseData } from '@/src/app/design-system/components/Calendar/parser/calendarParser';
import { eventApi } from '@generatesac/lib';

const TODAY = new Date();

Expand Down
24 changes: 12 additions & 12 deletions frontend/mobile/src/app/app/(tabs)/profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import {
faUser
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
import { Avatar } from '@rneui/base';

import { GlobalLayout } from '@/src/app/design-system/components/GlobalLayout/GlobalLayout';
import { resetAccessToken } from '@/src/store/slices/userSlice';
import { useAppDispatch, useAppSelector } from '@/src/store/store';

import { Box, Colors, SACColors, Spacing, Text } from '../../design-system';

Expand Down Expand Up @@ -43,6 +44,9 @@ const ProfileItem = ({ icon, text, textColor, onPress }: ProfileItemProps) => (
);

const ProfilePage = () => {
const dispatch = useAppDispatch();
const user = useAppSelector((state) => state.user);

return (
<GlobalLayout>
<SafeAreaView style={styles.container}>
Expand All @@ -52,27 +56,20 @@ const ProfilePage = () => {
gap="m"
alignItems="center"
>
<Avatar
source={{
uri: 'https://media1.popsugar-assets.com/files/thumbor/S6_lryTon-0orhMkLrw6m1yIFww=/1500x1500/filters:format_auto():quality(85):extract_cover()/2017/02/28/003/n/1922441/ace7eba458b602264e7940.39836479_edit_img_image_43244124_1488304081.jpg'
}}
size={60}
rounded
/>
<Box flexDirection="column" gap="xxs">
<Text variant="subheader-2">Quokka</Text>
<Text>quokka@northeastern.edu</Text>
<Text variant="subheader-2">{user.name}</Text>
<Text>{user.email}</Text>
</Box>
</Box>
<Box width="100%">
<ProfileItem
onPress={() => router.push('/user/detail/')}
onPress={() => router.push('/app/user/detail/')}
icon={faUser}
text="Edit Profile"
/>
<ProfileItem
icon={faHeart}
onPress={() => router.push('/user/interest/')}
onPress={() => router.push('/app/user/interest/')}
text="Edit Interests"
/>
<Box
Expand All @@ -85,6 +82,9 @@ const ProfilePage = () => {
icon={faSignOutAlt}
text="Logout"
textColor="darkRed"
onPress={() => {
dispatch(resetAccessToken());
}}
/>
</Box>
</SafeAreaView>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ interface UpcomingEventsProps {
export const UpcomingEvent: React.FC<UpcomingEventsProps> = ({ events }) => {
const renderEventCard = ({ item }: { item: Event }) => {
return (
<Pressable onPress={() => router.push(`/event/${item.id}`)}>
<Pressable onPress={() => router.push(`/app/event/${item.id}`)}>
<EventCard
variant="small"
event={item.name}
Expand Down

0 comments on commit 08f5271

Please sign in to comment.