← Назад к вопросам
Как передать токен авторизации в каждом запросе?
2.0 Middle🔥 191 комментариев
#JavaScript Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Передача токена авторизации в API запросах
Токен авторизации необходимо отправлять в заголовке Authorization каждого запроса. Есть несколько способов сделать это правильно.
1. Базовый способ - передача через headers
Просто добавь Authorization в каждый запрос:
const token = localStorage.getItem('authToken');
fetch('/api/users', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}` // Bearer token
}
})
.then(response => response.json())
.then(data => console.log(data));
2. Создай функцию-обёртку для fetch
Лучше всего вынести логику в отдельную функцию:
// lib/api.ts
const API_URL = process.env.REACT_APP_API_URL || 'https://api.example.com';
function getToken() {
return localStorage.getItem('authToken');
}
export async function apiCall(
endpoint: string,
options: RequestInit = {}
) {
const token = getToken();
const headers = new Headers(options.headers || {});
headers.set('Content-Type', 'application/json');
if (token) {
headers.set('Authorization', `Bearer ${token}`);
}
const response = await fetch(`${API_URL}${endpoint}`, {
...options,
headers
});
// Обработай 401 (Unauthorized)
if (response.status === 401) {
// Токен истёк, перенаправь на логин
localStorage.removeItem('authToken');
window.location.href = '/login';
}
if (!response.ok) {
throw new Error(`API Error: ${response.status}`);
}
return response.json();
}
// Использование:
export const api = {
users: {
getAll: () => apiCall('/api/users'),
getById: (id: string) => apiCall(`/api/users/${id}`),
create: (data: any) => apiCall('/api/users', {
method: 'POST',
body: JSON.stringify(data)
})
},
posts: {
getAll: () => apiCall('/api/posts'),
getById: (id: string) => apiCall(`/api/posts/${id}`)
}
};
3. Использование axios с перехватчиками
Если используешь axios, это проще всего:
// lib/api.ts
import axios from 'axios';
const apiClient = axios.create({
baseURL: process.env.REACT_APP_API_URL || 'https://api.example.com'
});
// Request перехватчик - добавляет токен ко ВСЕМ запросам
apiClient.interceptors.request.use(
(config) => {
const token = localStorage.getItem('authToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
// Response перехватчик - обработка ошибок авторизации
apiClient.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
// Токен истёк
localStorage.removeItem('authToken');
window.location.href = '/login';
}
return Promise.reject(error);
}
);
export default apiClient;
// Использование:
import apiClient from '@/lib/api';
// Токен добавляется автоматически!
apiClient.get('/api/users');
apiClient.post('/api/posts', { title: 'New Post' });
4. Context + useContext для хранения токена
Лучше всего хранить токен в контексте, а не в localStorage:
// contexts/AuthContext.tsx
import React, { createContext, useState, useCallback } from 'react';
interface AuthContextType {
token: string | null;
setToken: (token: string | null) => void;
isAuthenticated: boolean;
}
export const AuthContext = createContext<AuthContextType | null>(null);
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [token, setTokenState] = useState<string | null>(
localStorage.getItem('authToken')
);
const setToken = useCallback((newToken: string | null) => {
if (newToken) {
localStorage.setItem('authToken', newToken);
} else {
localStorage.removeItem('authToken');
}
setTokenState(newToken);
}, []);
return (
<AuthContext.Provider value={{
token,
setToken,
isAuthenticated: !!token
}}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const context = React.useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within AuthProvider');
}
return context;
}
// lib/api.ts
import { useAuth } from '@/contexts/AuthContext';
export function useApi() {
const { token } = useAuth();
return useCallback(async (
endpoint: string,
options: RequestInit = {}
) => {
const headers = new Headers(options.headers || {});
headers.set('Content-Type', 'application/json');
if (token) {
headers.set('Authorization', `Bearer ${token}`);
}
const response = await fetch(
`${process.env.REACT_APP_API_URL}${endpoint}`,
{ ...options, headers }
);
if (response.status === 401) {
// Токен истёк - выйти из системы
throw new Error('Unauthorized');
}
return response.json();
}, [token]);
}
5. Использование в компонентах
function UserList() {
const { token } = useAuth();
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchUsers = async () => {
try {
const response = await fetch('/api/users', {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
const data = await response.json();
setUsers(data);
} catch (error) {
console.error('Ошибка:', error);
} finally {
setLoading(false);
}
};
if (token) {
fetchUsers();
}
}, [token]); // Повторить запрос если изменился токен
if (loading) return <div>Загрузка...</div>;
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
6. Обновление токена при истечении (refresh token)
Если используешь refresh token:
const apiClient = axios.create({
baseURL: process.env.REACT_APP_API_URL
});
apiClient.interceptors.request.use((config) => {
const token = localStorage.getItem('authToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
apiClient.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;
// Если 401 и это не refresh запрос, попробуй обновить токен
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
const refreshToken = localStorage.getItem('refreshToken');
const response = await axios.post('/api/auth/refresh', {
refresh_token: refreshToken
});
const { access_token } = response.data;
localStorage.setItem('authToken', access_token);
// Повторить исходный запрос с новым токеном
originalRequest.headers.Authorization = `Bearer ${access_token}`;
return apiClient(originalRequest);
} catch (err) {
// Refresh не удался, перенаправь на логин
localStorage.removeItem('authToken');
localStorage.removeItem('refreshToken');
window.location.href = '/login';
return Promise.reject(err);
}
}
return Promise.reject(error);
}
);
7. Типизация с TypeScript
interface ApiRequestInit extends RequestInit {
headers?: Record<string, string>;
}
class ApiClient {
private baseURL: string;
private token: string | null = null;
constructor(baseURL: string) {
this.baseURL = baseURL;
this.token = localStorage.getItem('authToken');
}
setToken(token: string | null) {
this.token = token;
if (token) {
localStorage.setItem('authToken', token);
} else {
localStorage.removeItem('authToken');
}
}
private getHeaders(): Record<string, string> {
const headers: Record<string, string> = {
'Content-Type': 'application/json'
};
if (this.token) {
headers['Authorization'] = `Bearer ${this.token}`;
}
return headers;
}
async request<T>(
endpoint: string,
options: ApiRequestInit = {}
): Promise<T> {
const response = await fetch(`${this.baseURL}${endpoint}`, {
...options,
headers: {
...this.getHeaders(),
...options.headers
}
});
if (response.status === 401) {
this.setToken(null);
throw new Error('Unauthorized');
}
if (!response.ok) {
throw new Error(`HTTP Error: ${response.status}`);
}
return response.json();
}
get<T>(endpoint: string) {
return this.request<T>(endpoint, { method: 'GET' });
}
post<T>(endpoint: string, body: any) {
return this.request<T>(endpoint, {
method: 'POST',
body: JSON.stringify(body)
});
}
}
export const api = new ApiClient(
process.env.REACT_APP_API_URL || 'https://api.example.com'
);
Лучшие практики
- Никогда не храни чувствительные данные в localStorage - используй httpOnly cookies для более безопасного хранения
- Используй перехватчики (axios interceptors) для добавления токена ко всем запросам
- Обработай 401 ошибку - перенаправь пользователя на логин при истечении сессии
- Реализуй refresh token - чтобы пользователь не выходил из системы
- Передавай токен в заголовке Authorization - используй формат "Bearer {token}"
- Используй Context для хранения токена - вместо localStorage в каждом компоненте
- Типизируй API запросы - используй TypeScript для безопасности типов
Правильная организация авторизации - это критически важно для безопасности приложения.