Skip to content

Commit 8753023

Browse files
mjunaidcaclaude
andcommitted
feat(auth): Add refreshUserData function for profile sync
Implements Option 2 (Token Refresh on Profile Page) for immediate profile updates without requiring sign out/in. Changes: 1. Added refreshUserData() function to AuthContext - Fetches fresh user data from /oauth2/userinfo endpoint - Returns Promise<boolean> for success/failure handling - Updates session state with latest user information 2. Updated AUTH.md documentation - Added refreshUserData to available properties - New example: ProfilePage with auto-refresh on mount - New example: Manual refresh button - Use case explanation for profile synchronization Usage: ```tsx const { refreshUserData } = useAuth(); // Auto-refresh on page load useEffect(() => { refreshUserData(); }, []); // Manual refresh await refreshUserData(); ``` Benefits: - ✅ Immediate profile updates (no 6-hour token expiry wait) - ✅ No sign out/in required - ✅ Fresh data on demand - ✅ Better UX for profile management Related: Auth server profile edit page (auth-server commits) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent b0cad69 commit 8753023

File tree

2 files changed

+92
-2
lines changed

2 files changed

+92
-2
lines changed

robolearn-interface/AUTH.md

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,21 +160,73 @@ function SignOutButton() {
160160
<div>
161161
{/* Local sign out - user stays logged in at auth server */}
162162
<button onClick={() => signOut(false)}>Sign Out (Local)</button>
163-
163+
164164
{/* Global sign out - logs out from all apps */}
165165
<button onClick={() => signOut(true)}>Sign Out (Global)</button>
166166
</div>
167167
);
168168
}
169169
```
170170

171+
#### 6. Refresh User Data (After Profile Update)
172+
173+
```tsx
174+
import { useAuth } from '@/contexts/AuthContext';
175+
import { useEffect, useState } from 'react';
176+
177+
function ProfilePage() {
178+
const { session, refreshUserData } = useAuth();
179+
const [refreshing, setRefreshing] = useState(false);
180+
181+
// Option A: Auto-refresh on page load
182+
useEffect(() => {
183+
refreshUserData();
184+
}, []);
185+
186+
// Option B: Manual refresh button
187+
const handleRefresh = async () => {
188+
setRefreshing(true);
189+
const success = await refreshUserData();
190+
if (success) {
191+
alert('Profile data refreshed!');
192+
} else {
193+
alert('Failed to refresh profile data');
194+
}
195+
setRefreshing(false);
196+
};
197+
198+
if (!session) return <div>Please log in</div>;
199+
200+
return (
201+
<div>
202+
<h1>Profile</h1>
203+
<p><strong>Name:</strong> {session.user.name}</p>
204+
<p><strong>Email:</strong> {session.user.email}</p>
205+
<p><strong>Software Background:</strong> {session.user.softwareBackground}</p>
206+
<p><strong>Hardware Tier:</strong> {session.user.hardwareTier}</p>
207+
208+
<button onClick={handleRefresh} disabled={refreshing}>
209+
{refreshing ? 'Refreshing...' : 'Refresh Profile Data'}
210+
</button>
211+
212+
<a href={`${process.env.NEXT_PUBLIC_AUTH_URL}/account/profile`}>
213+
Edit Profile on Auth Server
214+
</a>
215+
</div>
216+
);
217+
}
218+
```
219+
220+
**Use Case**: After a user updates their profile on the auth server, call `refreshUserData()` to fetch the latest information without requiring sign out/in.
221+
171222
### Available Properties
172223

173224
The `useAuth()` hook returns:
174225

175226
- **`session`**: `Session | null` - Current session object containing user info and access token
176227
- **`isLoading`**: `boolean` - Whether authentication state is being checked
177228
- **`signOut`**: `(global?: boolean) => void` - Function to sign out the user
229+
- **`refreshUserData`**: `() => Promise<boolean>` - Fetches fresh user data from auth server (returns true on success)
178230

179231
### Notes
180232

robolearn-interface/src/contexts/AuthContext.tsx

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ interface AuthContextType {
2121
session: Session | null;
2222
isLoading: boolean;
2323
signOut: (global?: boolean) => void;
24+
refreshUserData: () => Promise<boolean>;
2425
}
2526

2627
const AuthContext = createContext<AuthContextType | undefined>(undefined);
@@ -171,8 +172,45 @@ export function AuthProvider({ children, authUrl, oauthClientId }: AuthProviderP
171172
}
172173
};
173174

175+
/**
176+
* Refresh user data from the auth server
177+
* Call this after profile updates to get the latest user information
178+
* @returns true if refresh succeeded, false otherwise
179+
*/
180+
const handleRefreshUserData = async (): Promise<boolean> => {
181+
try {
182+
const accessToken = localStorage.getItem('robolearn_access_token');
183+
184+
if (!accessToken) {
185+
console.warn('No access token available for refresh');
186+
return false;
187+
}
188+
189+
// Fetch fresh user data from /oauth2/userinfo endpoint
190+
const user = await fetchUserInfo(accessToken);
191+
192+
if (user) {
193+
// Update session with fresh user data
194+
setSession({ user, accessToken });
195+
console.log('✅ User data refreshed successfully');
196+
return true;
197+
} else {
198+
console.warn('⚠️ Failed to refresh user data');
199+
return false;
200+
}
201+
} catch (error) {
202+
console.error('❌ Error refreshing user data:', error);
203+
return false;
204+
}
205+
};
206+
174207
return (
175-
<AuthContext.Provider value={{ session, isLoading, signOut: handleSignOut }}>
208+
<AuthContext.Provider value={{
209+
session,
210+
isLoading,
211+
signOut: handleSignOut,
212+
refreshUserData: handleRefreshUserData
213+
}}>
176214
{children}
177215
</AuthContext.Provider>
178216
);

0 commit comments

Comments
 (0)