diff --git a/src/components/EventCreator/EventCreatorLink.tsx b/src/components/EventCreator/EventCreatorLink.tsx
index 9c73eda..ce0b10c 100644
--- a/src/components/EventCreator/EventCreatorLink.tsx
+++ b/src/components/EventCreator/EventCreatorLink.tsx
@@ -1,9 +1,11 @@
-import EventCreator from './EventCreator';
-import { IGroup } from '../types';
+import { useContext } from 'react';
+import { GroupContext } from '../Group/Group';
 import useToggle from '../useToggle';
+import EventCreator from './EventCreator';
 
-export default function EventCreatorLink({ group }: { group: IGroup }) {
+export default function EventCreatorLink() {
 	const [open, toggle] = useToggle(false);
+	const { group } = useContext(GroupContext);
 
 	return (
 		<div>
diff --git a/src/components/Group/Group.tsx b/src/components/Group/Group.tsx
index f0ef167..beb2a75 100644
--- a/src/components/Group/Group.tsx
+++ b/src/components/Group/Group.tsx
@@ -1,38 +1,59 @@
+import { createContext, useEffect } from 'react';
+import { getGroup } from '../api';
 import EventCreatorLink from '../EventCreator/EventCreatorLink';
 import EventStream from '../EventStream';
-import GroupSettingsLink from './GroupSettingsLink';
 import { IGroup } from '../types';
 import UILink from '../UI/UILink';
+import useImmutable from '../useImmutable';
 import GroupMembersLink from './GroupMembersLink';
+import GroupSettingsLink from './GroupSettingsLink';
+
+const DEFAULT_GROUP = (): IGroup => ({
+	id: 0,
+	name: '',
+	users: [],
+	events: [],
+	joinCode: null,
+});
+
+export const GroupContext = createContext({ group: DEFAULT_GROUP() });
+
+export default function Group({ id }: { id: number }) {
+	const [group, setGroup] = useImmutable<IGroup>(DEFAULT_GROUP());
+
+	useEffect(() => {
+		getGroup(id).then(setGroup);
+	}, [id, setGroup]);
 
-export default function Group({ group }: { group: IGroup }) {
 	return (
-		<div
-			style={{
-				textAlign: 'center',
-				maxWidth: '30rem',
-				marginLeft: 'auto',
-				marginRight: 'auto',
-			}}
-		>
-			<h1>{group.name}</h1>
-			<UILink href="/">Home</UILink>
-			<br />
-			<br />
-			<GroupMembersLink group={group} />
-			<br />
-			<GroupSettingsLink group={group} />
-			<br />
-			<EventCreatorLink group={group} />
-			<br />
+		<GroupContext.Provider value={{ group }}>
+			<div
+				style={{
+					textAlign: 'center',
+					maxWidth: '30rem',
+					marginLeft: 'auto',
+					marginRight: 'auto',
+				}}
+			>
+				<h1>{group.name}</h1>
+				<UILink href="/">Home</UILink>
+				<br />
+				<br />
+				<GroupMembersLink />
+				<br />
+				<GroupSettingsLink />
+				<br />
+				<EventCreatorLink />
+				<br />
 
-			{group.events.length > 0 ? (
-				<EventStream events={group.events} />
-			) : (
-				<span>
-					There are no events yet. Click 'create event' above to add one!
-				</span>
-			)}
-		</div>
+				{group.events.length > 0 ? (
+					<EventStream events={group.events} />
+				) : (
+					<span>
+						There are no events yet. Click 'create event' above to add one!
+					</span>
+				)}
+			</div>
+		</GroupContext.Provider>
 	);
 }
diff --git a/src/components/Group/GroupInviteCodeGenerator.tsx b/src/components/Group/GroupInviteCodeGenerator.tsx
new file mode 100644
index 0000000..caecffe
--- /dev/null
+++ b/src/components/Group/GroupInviteCodeGenerator.tsx
@@ -0,0 +1,72 @@
+import { useCallback, useContext } from 'react';
+import { lightgrey } from '../../lib/colors';
+import { generateCode, resetCode } from '../api';
+import UIButton from '../UI/UIButton';
+import { GroupContext } from './Group';
+
+export default function GroupInviteCodeGenerator() {
+	const { group } = useContext(GroupContext);
+
+	const generateJoinCode = useCallback(() => {
+		generateCode(group.id).then((code) => {
+			group.joinCode = code;
+		});
+	}, [group]);
+
+	const resetJoinCode = useCallback(() => {
+		resetCode(group.id).then((code) => {
+			group.joinCode = null;
+		});
+	}, [group]);
+
+	if (group.joinCode) {
+		return (
+			<>
+				<span>
+					Join this group with the code{' '}
+					<b>
+						<code>{group.joinCode}</code>
+					</b>
+				</span>
+				<div style={{ display: 'flex', justifyContent: 'space-between' }}>
+					<UIButton
+						onClick={resetJoinCode}
+						style={{
+							backgroundColor: lightgrey,
+							margin: '0.5rem',
+							flex: 1,
+						}}
+					>
+						Reset
+					</UIButton>
+					<UIButton
+						onClick={generateJoinCode}
+						style={{
+							backgroundColor: lightgrey,
+							margin: '0.5rem',
+							flex: 1,
+						}}
+					>
+						Regenerate
+					</UIButton>
+				</div>
+			</>
+		);
+	} else {
+		return (
+			<>
+				This group has no way for new members to join.
+				<UIButton
+					onClick={generateJoinCode}
+					style={{
+						backgroundColor: lightgrey,
+						marginTop: '0.5rem',
+						marginBottom: '0.5rem',
+					}}
+				>
+					Generate a code
+				</UIButton>
+			</>
+		);
+	}
+}
diff --git a/src/components/Group/GroupMembersLink.tsx b/src/components/Group/GroupMembersLink.tsx
index 4cd2b6e..9c030a2 100644
--- a/src/components/Group/GroupMembersLink.tsx
+++ b/src/components/Group/GroupMembersLink.tsx
@@ -1,11 +1,14 @@
-import { useState } from 'react';
-import { IGroup } from '../types';
+import { useContext, useState } from 'react';
 import UIPressable from '../UI/UIPressable';
 import UISecondaryBox from '../UI/UISecondaryBox';
+import { GroupContext } from './Group';
+import GroupInviteCodeGenerator from './GroupInviteCodeGenerator';
 
-export default function GroupMembersLink({ group }: { group: IGroup }) {
+export default function GroupMembersLink() {
 	const [open, setOpen] = useState(false);
 
+	const { group } = useContext(GroupContext);
+
 	const handleClick = () => setOpen(!open);
 
 	return (
@@ -16,6 +19,9 @@ export default function GroupMembersLink({ group }: { group: IGroup }) {
 					<br />
 					<UISecondaryBox>
 						<h1>Members</h1>
+
+						<GroupInviteCodeGenerator />
+
 						{group.users.map(({ name }) => (
 							<span key={name}>{name}</span>
 						))}
diff --git a/src/components/Group/GroupPage.tsx b/src/components/Group/GroupPage.tsx
index bf69432..b7caf0e 100644
--- a/src/components/Group/GroupPage.tsx
+++ b/src/components/Group/GroupPage.tsx
@@ -1,43 +1,8 @@
-import { useEffect, useState } from 'react';
 import { useParams } from 'react-router';
-import { Link } from 'react-router-dom';
-import { getGroup } from '../api';
-import { IGroup } from '../types';
 import Group from './Group';
 
 export default function GroupPage() {
 	const { id } = useParams<{ id: string }>();
-	const [loading, setLoading] = useState(true);
-	const [group, setGroup] = useState<IGroup | null>(null);
 
-	useEffect(() => {
-		if (isNaN(+id)) {
-			setLoading(false);
-			return;
-		}
-
-		async function load() {
-			setLoading(true);
-			getGroup(+id)
-				.then(setGroup)
-				.finally(() => setLoading(false));
-		}
-
-		load();
-	}, [id]);
-
-	if (!group && !loading) {
-		return (
-			<div style={{ textAlign: 'center' }}>
-				<h1>Group Not Found</h1>
-				<Link to="/">Home</Link>
-			</div>
-		);
-	}
-
-	if (!group) {
-		return null;
-	}
-
-	return <Group group={group} />;
+	return <Group id={+id} />;
 }
diff --git a/src/components/Group/GroupSettingsLink.tsx b/src/components/Group/GroupSettingsLink.tsx
index 7b97911..a3ad286 100644
--- a/src/components/Group/GroupSettingsLink.tsx
+++ b/src/components/Group/GroupSettingsLink.tsx
@@ -1,9 +1,11 @@
-import { IGroup } from '../types';
+import { useContext } from 'react';
 import useToggle from '../useToggle';
+import { GroupContext } from './Group';
 import GroupSettings from './GroupSettings';
 
-export default function GroupSettingsLink({ group }: { group: IGroup }) {
+export default function GroupSettingsLink() {
 	const [open, toggle] = useToggle(false);
+	const { group } = useContext(GroupContext);
 
 	return (
 		<div>
diff --git a/src/components/api.ts b/src/components/api.ts
index d4c98a5..b8c9de0 100644
--- a/src/components/api.ts
+++ b/src/components/api.ts
@@ -166,7 +166,9 @@ export async function joinGroup(id: number, code: string) {
 }
 
 export async function generateCode(groupId: number) {
-	return await post('/groups/' + groupId + '/generate_code', {});
+	const { code } = await post(`/groups/${groupId}/generate_code`, {});
+
+	return code;
 }
 
 export async function resetCode(groupId: number) {
diff --git a/src/components/types.ts b/src/components/types.ts
index afa9c89..e6a05eb 100644
--- a/src/components/types.ts
+++ b/src/components/types.ts
@@ -54,6 +54,7 @@ export type IGroup = {
 		id: number;
 		name: string;
 	}[];
+	joinCode: string | null;
 };
 
 /**