Skip to content

Commit e8d529c

Browse files
fix: Google SSO
1 parent 5291b26 commit e8d529c

File tree

9 files changed

+49
-38
lines changed

9 files changed

+49
-38
lines changed

.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
AZURE_COSMOSDB_DATABASE=
22
AZURE_COSMOSDB_ENDPOINT=
33
AZURE_COSMOSDB_KEY=
4+
NEXT_PUBLIC_APPWRITE_ENDPOINT=
5+
NEXT_PUBLIC_APPWRITE_PROJECT_ID=

AUTHENTICATION_SETUP.md

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,29 @@ This guide will help you set up Appwrite authentication for your Practice Exams
6060
Create a `.env.local` file in your project root with:
6161

6262
```bash
63-
NEXT_PUBLIC_APPWRITE_ENDPOINT=https://cloud.appwrite.io/v1
64-
NEXT_PUBLIC_APPWRITE_PROJECT_ID=your_project_id_here
63+
APPWRITE_PUBLIC_ENDPOINT=https://[REGION].cloud.appwrite.io/v1
64+
APPWRITE_PROJECT_ID=your_project_id_here
6565
```
6666

6767
Replace `your_project_id_here` with your actual Appwrite project ID.
6868

6969
## Step 4: Update Callback URLs
7070

71-
In your Appwrite project settings, add these callback URLs:
71+
In your Appwrite project settings, you need to configure callback URLs for OAuth providers:
7272

73-
- **Success URL**: `https://yourdomain.com/auth/callback?success=true`
74-
- **Failure URL**: `https://yourdomain.com/auth/callback?failure=true`
73+
### For Google OAuth:
74+
75+
1. Go to **Auth****OAuth2 Providers****Google**
76+
2. In the Google OAuth configuration, you'll see a **Redirect URL** field
77+
3. Set this to: `https://yourdomain.com/auth/callback`
78+
79+
### For Apple OAuth:
80+
81+
1. Go to **Auth****OAuth2 Providers****Apple**
82+
2. In the Apple OAuth configuration, you'll see a **Redirect URL** field
83+
3. Set this to: `https://yourdomain.com/auth/callback`
84+
85+
**Note**: The success/failure URLs mentioned in the original documentation are not standard Appwrite settings. Appwrite handles OAuth redirects automatically to the redirect URL you specify above. The success/failure parameters are handled by your application logic in the callback route.
7586

7687
## Step 5: Test Authentication
7788

app/auth/callback/page.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import { useEffect, useState } from "react";
44
import { useRouter, useSearchParams } from "next/navigation";
55
import { AuthService } from "../../../lib/appwrite/auth";
66
import LoadingIndicator from "../../../components/LoadingIndicator";
7+
import { useAuth } from "../../../contexts/AuthContext";
78

89
export default function AuthCallback() {
910
const router = useRouter();
1011
const searchParams = useSearchParams();
12+
const { refreshUser } = useAuth();
1113
const [status, setStatus] = useState<"loading" | "success" | "error">(
1214
"loading",
1315
);
@@ -30,6 +32,8 @@ export default function AuthCallback() {
3032
}
3133

3234
if (success === "true") {
35+
// Refresh auth context to update authentication state
36+
await refreshUser();
3337
setStatus("success");
3438
setMessage("Authentication successful! Redirecting...");
3539
setTimeout(() => router.push("/"), 2000);
@@ -40,6 +44,8 @@ export default function AuthCallback() {
4044
if (userId && secret) {
4145
const result = await AuthService.updateEmailSession(userId, secret);
4246
if (result.success) {
47+
// Refresh auth context to update authentication state
48+
await refreshUser();
4349
setStatus("success");
4450
setMessage("Email verified successfully! Redirecting...");
4551
setTimeout(() => router.push("/"), 2000);
@@ -61,7 +67,7 @@ export default function AuthCallback() {
6167
};
6268

6369
handleCallback();
64-
}, [router, searchParams]);
70+
}, [router, searchParams, refreshUser]);
6571

6672
if (status === "loading") {
6773
return (

components/TopNav.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,15 +86,17 @@ const TopNav = () => {
8686
</button>
8787

8888
{showUserMenu && (
89-
<div className="absolute right-0 mt-2 w-48 bg-slate-800 rounded-lg shadow-lg border border-slate-600 z-50">
89+
<div className="absolute right-0 mt-2 w-64 bg-slate-800 rounded-lg shadow-lg border border-slate-600 z-50">
9090
<div className="py-2">
91-
<div className="px-4 py-2 text-sm text-slate-300 border-b border-slate-600">
92-
Signed in as{" "}
93-
<span className="font-medium">{user.email}</span>
91+
<div className="px-4 py-2 text-sm text-slate-300 border-b border-slate-600 text-center">
92+
<div>Signed in as</div>
93+
<div className="font-medium text-white mt-1 break-all">
94+
{user.email}
95+
</div>
9496
</div>
9597
<button
9698
onClick={handleSignOut}
97-
className="w-full text-left px-4 py-2 text-sm text-slate-300 hover:bg-slate-700 transition-colors"
99+
className="w-full text-center px-4 py-2 text-sm text-slate-300 hover:bg-slate-700 transition-colors"
98100
>
99101
Sign Out
100102
</button>

lib/appwrite/auth.ts

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export class AuthService {
1919
email: string,
2020
): Promise<{ success: boolean; error?: AuthError }> {
2121
try {
22-
await account.createMagicURLSession(
22+
await (account as any).createMagicURLSession(
2323
ID.unique(),
2424
email,
2525
`${window.location.origin}/auth/callback`,
@@ -36,23 +36,6 @@ export class AuthService {
3636
}
3737
}
3838

39-
static async createEmailOTPSession(
40-
email: string,
41-
): Promise<{ success: boolean; error?: AuthError }> {
42-
try {
43-
await account.createEmailSession(email, "123456"); // 6-digit OTP
44-
return { success: true };
45-
} catch (error: any) {
46-
return {
47-
success: false,
48-
error: {
49-
message: error.message || "Failed to send OTP",
50-
code: error.code,
51-
},
52-
};
53-
}
54-
}
55-
5639
static async updateEmailSession(
5740
userId: string,
5841
secret: string,
@@ -79,11 +62,14 @@ export class AuthService {
7962
try {
8063
const redirectUrl = `${window.location.origin}/auth/callback`;
8164
const url = await account.createOAuth2Session(
82-
"google",
65+
"google" as any,
8366
redirectUrl,
8467
redirectUrl,
8568
);
86-
window.location.href = url.toString();
69+
70+
if (typeof url === "string") {
71+
window.location.href = url;
72+
}
8773
return { success: true };
8874
} catch (error: any) {
8975
return {
@@ -104,11 +90,14 @@ export class AuthService {
10490
try {
10591
const redirectUrl = `${window.location.origin}/auth/callback`;
10692
const url = await account.createOAuth2Session(
107-
"apple",
93+
"apple" as any,
10894
redirectUrl,
10995
redirectUrl,
11096
);
111-
window.location.href = url.toString();
97+
98+
if (typeof url === "string") {
99+
window.location.href = url;
100+
}
112101
return { success: true };
113102
} catch (error: any) {
114103
return {

lib/appwrite/config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import { Client, Account, Databases } from "appwrite";
22

33
const client = new Client()
44
.setEndpoint(
5-
process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT || "https://cloud.appwrite.io/v1",
5+
process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT ||
6+
"https://fra.cloud.appwrite.io/v1",
67
)
78
.setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID || "");
89

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "practice-exams-platform",
3-
"version": "1.3.2",
3+
"version": "1.4.0",
44
"private": true,
55
"engines": {
66
"node": "20.x"

public/sw.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)