or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

admin-core.mdadvanced.mdauth.mddata-management.mddetail-views.mdforms-inputs.mdi18n.mdindex.mdlayout-navigation.mdlists-data-display.mdui-components.md

auth.mddocs/

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.