0
# Authentication & Authorization
1
2
React Admin provides a flexible authentication and authorization system that handles login/logout flows, session management, and permission-based access control. The system is backend-agnostic and works with any authentication service through auth providers.
3
4
## Auth Provider Interface
5
6
The auth provider defines how your application handles authentication and authorization.
7
8
```typescript { .api }
9
import { AuthProvider } from 'react-admin';
10
11
interface AuthProvider {
12
login: (params: any) => Promise<any>;
13
logout: (params?: any) => Promise<void>;
14
checkAuth: (params?: any) => Promise<void>;
15
checkError: (error: any) => Promise<void>;
16
getPermissions: (params?: any) => Promise<any>;
17
getIdentity?: () => Promise<UserIdentity>;
18
handleCallback?: () => Promise<AuthRedirectResult | void | any>;
19
}
20
21
interface UserIdentity {
22
id: string | number;
23
fullName?: string;
24
avatar?: string;
25
[key: string]: any;
26
}
27
28
interface AuthRedirectResult {
29
redirectTo?: string | false;
30
}
31
```
32
33
### Auth Provider Methods
34
35
#### login
36
Handles user authentication. Called when the login form is submitted.
37
38
**Parameters:**
39
- `params`: Login credentials (usually `{ username, password }`)
40
41
**Returns:** Promise that resolves on successful login, rejects on failure
42
43
#### logout
44
Handles user logout and cleanup.
45
46
**Parameters:**
47
- `params`: Optional logout parameters
48
49
**Returns:** Promise that resolves when logout is complete
50
51
#### checkAuth
52
Checks if the user is authenticated. Called on app startup and route changes.
53
54
**Parameters:**
55
- `params`: Optional parameters for auth check
56
57
**Returns:** Promise that resolves if authenticated, rejects if not
58
59
#### checkError
60
Handles authentication errors from API responses.
61
62
**Parameters:**
63
- `error`: Error object from failed API request
64
65
**Returns:** Promise that resolves to continue, rejects to logout user
66
67
#### getPermissions
68
Retrieves user permissions for authorization.
69
70
**Parameters:**
71
- `params`: Optional parameters
72
73
**Returns:** Promise resolving to permissions object
74
75
#### getIdentity
76
Gets user identity information for display.
77
78
**Returns:** Promise resolving to `UserIdentity` object
79
80
### Basic Auth Provider Example
81
82
```typescript
83
import { AuthProvider } from 'react-admin';
84
85
const authProvider: AuthProvider = {
86
login: async ({ username, password }) => {
87
const request = new Request('/api/login', {
88
method: 'POST',
89
body: JSON.stringify({ username, password }),
90
headers: new Headers({ 'Content-Type': 'application/json' }),
91
});
92
93
const response = await fetch(request);
94
if (response.status < 200 || response.status >= 300) {
95
throw new Error(response.statusText);
96
}
97
98
const { token } = await response.json();
99
localStorage.setItem('token', token);
100
},
101
102
logout: async () => {
103
localStorage.removeItem('token');
104
},
105
106
checkAuth: async () => {
107
const token = localStorage.getItem('token');
108
if (!token) {
109
throw new Error('No token found');
110
}
111
},
112
113
checkError: async (error) => {
114
const status = error.status;
115
if (status === 401 || status === 403) {
116
localStorage.removeItem('token');
117
throw error;
118
}
119
},
120
121
getPermissions: async () => {
122
const token = localStorage.getItem('token');
123
if (!token) return null;
124
125
// Decode token or make API call to get permissions
126
return { role: 'admin' };
127
},
128
129
getIdentity: async () => {
130
const token = localStorage.getItem('token');
131
if (!token) throw new Error('No token');
132
133
const response = await fetch('/api/me', {
134
headers: { Authorization: `Bearer ${token}` }
135
});
136
137
const user = await response.json();
138
return {
139
id: user.id,
140
fullName: user.name,
141
avatar: user.avatar
142
};
143
}
144
};
145
```
146
147
## Authentication Hooks
148
149
### useAuthProvider
150
151
Access the auth provider instance directly.
152
153
```typescript { .api }
154
import { useAuthProvider } from 'react-admin';
155
156
const useAuthProvider: () => AuthProvider | undefined;
157
```
158
159
### useLogin
160
161
Get the login function for programmatic authentication.
162
163
```typescript { .api }
164
import { useLogin } from 'react-admin';
165
166
type LoginFunction = (params: any, pathName?: string) => Promise<any>;
167
168
const useLogin: () => LoginFunction;
169
```
170
171
#### Usage Example
172
173
```typescript
174
import { useLogin, useNotify } from 'react-admin';
175
176
const CustomLoginButton = () => {
177
const login = useLogin();
178
const notify = useNotify();
179
180
const handleLogin = async () => {
181
try {
182
await login({ username: 'admin', password: 'password' });
183
notify('Login successful');
184
} catch (error) {
185
notify('Login failed', { type: 'error' });
186
}
187
};
188
189
return <button onClick={handleLogin}>Login</button>;
190
};
191
```
192
193
### useLogout
194
195
Get the logout function for programmatic logout.
196
197
```typescript { .api }
198
import { useLogout } from 'react-admin';
199
200
type LogoutFunction = (params?: any, redirectTo?: string, redirectToCurrentLocationAfterLogin?: boolean) => Promise<any>;
201
202
const useLogout: () => LogoutFunction;
203
```
204
205
#### Usage Example
206
207
```typescript
208
import { useLogout } from 'react-admin';
209
210
const CustomLogoutButton = () => {
211
const logout = useLogout();
212
213
const handleLogout = () => {
214
logout({}, '/login');
215
};
216
217
return <button onClick={handleLogout}>Logout</button>;
218
};
219
```
220
221
### useAuthState
222
223
Get the current authentication state.
224
225
```typescript { .api }
226
import { useAuthState } from 'react-admin';
227
228
interface AuthStateResult {
229
isLoading: boolean;
230
authenticated?: boolean;
231
}
232
233
const useAuthState: () => AuthStateResult;
234
```
235
236
### useAuthenticated
237
238
Hook that throws an error if user is not authenticated, useful for protecting components.
239
240
```typescript { .api }
241
import { useAuthenticated } from 'react-admin';
242
243
const useAuthenticated: () => void;
244
```
245
246
#### Usage Example
247
248
```typescript
249
import { useAuthenticated } from 'react-admin';
250
251
const ProtectedComponent = () => {
252
useAuthenticated(); // Redirects to login if not authenticated
253
254
return <div>This content is only visible to authenticated users</div>;
255
};
256
```
257
258
### useCheckAuth
259
260
Perform authentication checks programmatically.
261
262
```typescript { .api }
263
import { useCheckAuth } from 'react-admin';
264
265
const useCheckAuth: () => (params?: any, logoutOnFailure?: boolean, redirectTo?: string) => Promise<any>;
266
```
267
268
### useGetIdentity
269
270
Get the current user's identity information.
271
272
```typescript { .api }
273
import { useGetIdentity } from 'react-admin';
274
275
const useGetIdentity: () => {
276
data: UserIdentity | undefined;
277
isLoading: boolean;
278
error: any;
279
refetch: () => void;
280
};
281
```
282
283
#### Usage Example
284
285
```typescript
286
import { useGetIdentity } from 'react-admin';
287
288
const UserProfile = () => {
289
const { data: identity, isLoading } = useGetIdentity();
290
291
if (isLoading) return <div>Loading...</div>;
292
if (!identity) return <div>Not logged in</div>;
293
294
return (
295
<div>
296
<img src={identity.avatar} alt="Avatar" />
297
<h2>Welcome, {identity.fullName}</h2>
298
</div>
299
);
300
};
301
```
302
303
## Authorization Hooks
304
305
### usePermissions
306
307
Get the current user's permissions.
308
309
```typescript { .api }
310
import { usePermissions } from 'react-admin';
311
312
const usePermissions: () => {
313
permissions: any;
314
isLoading: boolean;
315
error: any;
316
refetch: () => void;
317
};
318
```
319
320
#### Usage Example
321
322
```typescript
323
import { usePermissions } from 'react-admin';
324
325
const AdminPanel = () => {
326
const { permissions, isLoading } = usePermissions();
327
328
if (isLoading) return <div>Loading permissions...</div>;
329
330
const canDeletePosts = permissions && permissions.posts && permissions.posts.delete;
331
332
return (
333
<div>
334
<h2>Admin Panel</h2>
335
{canDeletePosts && <button>Delete Post</button>}
336
</div>
337
);
338
};
339
```
340
341
### usePermissionsOptimized
342
343
Optimized version of `usePermissions` that doesn't trigger re-renders.
344
345
```typescript { .api }
346
import { usePermissionsOptimized } from 'react-admin';
347
348
const usePermissionsOptimized: () => any;
349
```
350
351
## Authentication Components
352
353
### Authenticated
354
355
Component that renders children only if user is authenticated.
356
357
```typescript { .api }
358
import { Authenticated } from 'react-admin';
359
360
interface AuthenticatedProps {
361
children: React.ReactNode;
362
loading?: React.ComponentType;
363
requireAuth?: boolean;
364
}
365
366
const Authenticated: React.FC<AuthenticatedProps>;
367
```
368
369
#### Usage Example
370
371
```typescript
372
import { Authenticated } from 'react-admin';
373
374
const App = () => (
375
<div>
376
<h1>Public Content</h1>
377
<Authenticated>
378
<div>This content requires authentication</div>
379
</Authenticated>
380
</div>
381
);
382
```
383
384
### WithPermissions
385
386
Higher-order component for conditional rendering based on permissions.
387
388
```typescript { .api }
389
import { WithPermissions } from 'react-admin';
390
391
interface WithPermissionsProps {
392
authParams?: any;
393
component?: React.ComponentType;
394
render?: (params: { permissions: any }) => React.ReactElement;
395
children?: (params: { permissions: any }) => React.ReactElement;
396
[key: string]: any;
397
}
398
399
const WithPermissions: React.FC<WithPermissionsProps>;
400
```
401
402
#### Usage Example
403
404
```typescript
405
import { WithPermissions } from 'react-admin';
406
407
const ConditionalButton = () => (
408
<WithPermissions
409
render={({ permissions }) =>
410
permissions && permissions.canEdit ?
411
<button>Edit</button> :
412
<span>Read-only</span>
413
}
414
/>
415
);
416
```
417
418
## Login Components
419
420
### Login
421
422
Default login page component.
423
424
```typescript { .api }
425
import { Login } from 'react-admin';
426
427
interface LoginProps {
428
backgroundImage?: string;
429
children?: React.ReactNode;
430
className?: string;
431
sx?: any;
432
}
433
434
const Login: React.FC<LoginProps>;
435
```
436
437
### LoginForm
438
439
Login form component that can be used in custom login pages.
440
441
```typescript { .api }
442
import { LoginForm } from 'react-admin';
443
444
interface LoginFormProps {
445
redirectTo?: string;
446
children?: React.ReactNode;
447
className?: string;
448
sx?: any;
449
}
450
451
const LoginForm: React.FC<LoginFormProps>;
452
```
453
454
#### Custom Login Page Example
455
456
```typescript
457
import { Login, LoginForm } from 'react-admin';
458
459
const CustomLoginPage = () => (
460
<Login backgroundImage="/login-background.jpg">
461
<LoginForm>
462
<div style={{ marginTop: '1em' }}>
463
<a href="/forgot-password">Forgot password?</a>
464
</div>
465
</LoginForm>
466
</Login>
467
);
468
```
469
470
### Logout
471
472
Logout component for triggering logout.
473
474
```typescript { .api }
475
import { Logout } from 'react-admin';
476
477
interface LogoutProps {
478
className?: string;
479
redirectTo?: string;
480
icon?: React.ReactElement;
481
sx?: any;
482
}
483
484
const Logout: React.FC<LogoutProps>;
485
```
486
487
## OAuth and External Auth
488
489
### useHandleAuthCallback
490
491
Handle OAuth authentication callbacks.
492
493
```typescript { .api }
494
import { useHandleAuthCallback } from 'react-admin';
495
496
const useHandleAuthCallback: () => {
497
data: AuthRedirectResult | undefined;
498
isLoading: boolean;
499
error: any;
500
};
501
```
502
503
#### OAuth Example
504
505
```typescript
506
import { useHandleAuthCallback } from 'react-admin';
507
import { useEffect } from 'react';
508
509
const AuthCallback = () => {
510
const { data, isLoading, error } = useHandleAuthCallback();
511
512
useEffect(() => {
513
if (data && data.redirectTo) {
514
window.location.href = data.redirectTo;
515
}
516
}, [data]);
517
518
if (isLoading) return <div>Processing authentication...</div>;
519
if (error) return <div>Authentication error</div>;
520
521
return <div>Authentication successful</div>;
522
};
523
```
524
525
## Error Handling
526
527
### useLogoutIfAccessDenied
528
529
Automatically logout users when access is denied.
530
531
```typescript { .api }
532
import { useLogoutIfAccessDenied } from 'react-admin';
533
534
const useLogoutIfAccessDenied: () => (error?: any) => Promise<boolean>;
535
```
536
537
#### Usage Example
538
539
```typescript
540
import { useLogoutIfAccessDenied, useDataProvider } from 'react-admin';
541
542
const SecureComponent = () => {
543
const dataProvider = useDataProvider();
544
const logoutIfAccessDenied = useLogoutIfAccessDenied();
545
546
const fetchSecureData = async () => {
547
try {
548
await dataProvider.getList('secure-resource', {});
549
} catch (error) {
550
// Automatically logout if 401/403
551
const shouldLogout = await logoutIfAccessDenied(error);
552
if (!shouldLogout) {
553
// Handle other errors
554
console.error('Fetch error:', error);
555
}
556
}
557
};
558
559
return <button onClick={fetchSecureData}>Load Secure Data</button>;
560
};
561
```
562
563
## Advanced Authentication Examples
564
565
### JWT Auth Provider
566
567
```typescript
568
import { AuthProvider } from 'react-admin';
569
import { jwtDecode } from 'jwt-decode';
570
571
const jwtAuthProvider: AuthProvider = {
572
login: async ({ username, password }) => {
573
const request = new Request('/api/auth/login', {
574
method: 'POST',
575
body: JSON.stringify({ username, password }),
576
headers: new Headers({ 'Content-Type': 'application/json' }),
577
});
578
579
const response = await fetch(request);
580
if (response.status < 200 || response.status >= 300) {
581
throw new Error(response.statusText);
582
}
583
584
const { token, refreshToken } = await response.json();
585
localStorage.setItem('token', token);
586
localStorage.setItem('refreshToken', refreshToken);
587
588
return { redirectTo: '/dashboard' };
589
},
590
591
logout: async () => {
592
const token = localStorage.getItem('token');
593
if (token) {
594
// Notify server of logout
595
await fetch('/api/auth/logout', {
596
method: 'POST',
597
headers: { Authorization: `Bearer ${token}` }
598
});
599
}
600
601
localStorage.removeItem('token');
602
localStorage.removeItem('refreshToken');
603
return { redirectTo: '/login' };
604
},
605
606
checkAuth: async () => {
607
const token = localStorage.getItem('token');
608
if (!token) {
609
throw new Error('No token found');
610
}
611
612
try {
613
const decodedToken = jwtDecode(token);
614
if (decodedToken.exp * 1000 < Date.now()) {
615
// Token expired, try to refresh
616
await refreshToken();
617
}
618
} catch (error) {
619
localStorage.removeItem('token');
620
throw new Error('Invalid token');
621
}
622
},
623
624
checkError: async (error) => {
625
const status = error.status;
626
if (status === 401 || status === 403) {
627
localStorage.removeItem('token');
628
localStorage.removeItem('refreshToken');
629
throw error;
630
}
631
},
632
633
getPermissions: async () => {
634
const token = localStorage.getItem('token');
635
if (!token) return null;
636
637
try {
638
const decodedToken = jwtDecode(token);
639
return decodedToken.permissions;
640
} catch (error) {
641
return null;
642
}
643
},
644
645
getIdentity: async () => {
646
const token = localStorage.getItem('token');
647
if (!token) throw new Error('No token');
648
649
const decodedToken = jwtDecode(token);
650
return {
651
id: decodedToken.sub,
652
fullName: decodedToken.name,
653
avatar: decodedToken.avatar
654
};
655
}
656
};
657
658
const refreshToken = async () => {
659
const refreshToken = localStorage.getItem('refreshToken');
660
if (!refreshToken) throw new Error('No refresh token');
661
662
const response = await fetch('/api/auth/refresh', {
663
method: 'POST',
664
headers: {
665
'Content-Type': 'application/json',
666
'Authorization': `Bearer ${refreshToken}`
667
}
668
});
669
670
if (!response.ok) throw new Error('Token refresh failed');
671
672
const { token } = await response.json();
673
localStorage.setItem('token', token);
674
};
675
```
676
677
### Role-Based Access Control
678
679
```typescript
680
import { usePermissions, WithPermissions } from 'react-admin';
681
682
// Permission-based component rendering
683
const AdminOnlyButton = () => (
684
<WithPermissions
685
render={({ permissions }) =>
686
permissions?.role === 'admin' ?
687
<button>Admin Action</button> :
688
null
689
}
690
/>
691
);
692
693
// Hook-based permission checking
694
const useHasPermission = (resource: string, action: string) => {
695
const { permissions } = usePermissions();
696
697
return permissions &&
698
permissions[resource] &&
699
permissions[resource][action];
700
};
701
702
const PostActions = () => {
703
const canEdit = useHasPermission('posts', 'edit');
704
const canDelete = useHasPermission('posts', 'delete');
705
706
return (
707
<div>
708
{canEdit && <button>Edit</button>}
709
{canDelete && <button>Delete</button>}
710
</div>
711
);
712
};
713
```
714
715
React Admin's authentication system provides flexible, secure user management that adapts to various backend authentication strategies while maintaining excellent user experience through optimistic updates and intelligent session management.