19 KiB
19 KiB
Authentication API Documentation
Bu doküman, Django REST API'nin authentication endpoint'lerini ve kullanım örneklerini içerir.
📋 İçindekiler
- Genel Bilgiler
- Registration (Kayıt)
- Email Activation (Aktivasyon)
- Login (Giriş)
- Token Refresh
- Social Authentication
- User Profile
- Password Reset
- Frontend Entegrasyonu
- Error Handling
Genel Bilgiler
Base URL: http://localhost:8000/api/v1/
Authentication: JWT Bearer Token
Authorization: Bearer <access_token>
Content-Type: application/json
Rate Limiting
- Anonymous users: 100 requests/hour
- Authenticated users: 1000 requests/hour
Registration (Kayıt)
Endpoint
POST /api/v1/auth/users/
Request Body
{
"email": "user@example.com",
"password": "StrongP@ssw0rd123",
"re_password": "StrongP@ssw0rd123",
"first_name": "Ali",
"last_name": "Veli"
}
Response (201 Created)
{
"id": 1,
"email": "user@example.com",
"first_name": "Ali",
"last_name": "Veli"
}
Önemli Notlar
- Kullanıcı oluşturulur ancak
is_active=Falseolarak ayarlanır - Aktivasyon emaili otomatik gönderilir
- Kullanıcı email aktivasyonu yapmadan login olamaz
- Password minimum 8 karakter olmalı ve güçlü olmalı
Curl Example
curl -X POST http://localhost:8000/api/v1/auth/users/ \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "StrongP@ssw0rd123",
"re_password": "StrongP@ssw0rd123",
"first_name": "Ali",
"last_name": "Veli"
}'
Email Activation (Aktivasyon)
Endpoint
POST /api/v1/auth/users/activation/
Request Body
{
"uid": "MQ",
"token": "c4h7vu-a8f3d2e1c4b5a6d7e8f9g0h1"
}
Response (204 No Content)
Başarılı aktivasyon sonrası response body boş döner.
Önemli Notlar
uidvetokenaktivasyon emailindeki linkten alınır- Token 24 saat geçerlidir
- Başarılı aktivasyon sonrası
is_active=Trueolur - Kullanıcı artık login olabilir
Email Link Format
http://localhost:3000/auth/activate/{uid}/{token}/
Frontend bu linki yakalayıp backend'e POST request yapmalı.
Curl Example
curl -X POST http://localhost:8000/api/v1/auth/users/activation/ \
-H "Content-Type: application/json" \
-d '{
"uid": "MQ",
"token": "c4h7vu-a8f3d2e1c4b5a6d7e8f9g0h1"
}'
Resend Activation Email
POST /api/v1/auth/users/resend_activation/
Request Body:
{
"email": "user@example.com"
}
Login (Giriş)
Endpoint
POST /api/v1/auth/jwt/create/
Request Body
{
"email": "user@example.com",
"password": "StrongP@ssw0rd123"
}
Response (200 OK)
{
"access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Token Bilgileri
- Access Token: 60 dakika geçerli
- Refresh Token: 7 gün geçerli
- Token rotation aktif (refresh kullanıldığında yeni refresh token döner)
Önemli Notlar
- Kullanıcı
is_active=Falseise login başarısız olur - Hatalı email/password için 401 Unauthorized döner
Curl Example
curl -X POST http://localhost:8000/api/v1/auth/jwt/create/ \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "StrongP@ssw0rd123"
}'
Error Response (401 Unauthorized)
{
"detail": "No active account found with the given credentials"
}
Token Refresh
Endpoint
POST /api/v1/auth/jwt/refresh/
Request Body
{
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Response (200 OK)
{
"access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Önemli Notlar
- Yeni access token ve yeni refresh token döner (rotation)
- Eski refresh token blacklist'e eklenir
- Refresh token expire olduysa 401 döner
Curl Example
curl -X POST http://localhost:8000/api/v1/auth/jwt/refresh/ \
-H "Content-Type: application/json" \
-d '{
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'
Social Authentication
Supported Providers
- Google:
google-oauth2 - GitHub:
github - Facebook:
facebook
Endpoint
POST /api/v1/auth/social/<provider>/
Request Body
{
"access_token": "ya29.a0AfH6SMBx..."
}
Response (200 OK)
{
"access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"email": "user@example.com",
"first_name": "Ali",
"last_name": "Veli",
"is_active": true,
"date_joined": "2025-12-12T21:30:00Z"
}
}
Önemli Notlar
- Social login ile gelen kullanıcılar otomatik aktif (
is_active=True) - Email aktivasyon gerekmez
- Kullanıcı yoksa otomatik oluşturulur
- Provider'dan email alınamazsa hata döner
Google OAuth2 Example
1. Frontend'de Google OAuth
// Google OAuth2 ile token al
const googleUser = await gapi.auth2.getAuthInstance().signIn();
const accessToken = googleUser.getAuthResponse().access_token;
// Backend'e gönder
const response = await fetch('http://localhost:8000/api/v1/auth/social/google-oauth2/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
access_token: accessToken
})
});
const data = await response.json();
// data.access, data.refresh, data.user
2. Curl Example
curl -X POST http://localhost:8000/api/v1/auth/social/google-oauth2/ \
-H "Content-Type: application/json" \
-d '{
"access_token": "ya29.a0AfH6SMBx..."
}'
GitHub OAuth2 Example
curl -X POST http://localhost:8000/api/v1/auth/social/github/ \
-H "Content-Type: application/json" \
-d '{
"access_token": "gho_16C7e42F292c6912E7710c838347Ae178B4a"
}'
Error Responses
Invalid Provider (400)
{
"error": "Invalid provider. Must be one of: google-oauth2, github, facebook"
}
Missing Token (400)
{
"error": "access_token is required"
}
Authentication Failed (401)
{
"error": "Authentication failed. Invalid token."
}
Email Not Provided (403)
{
"error": "Authentication forbidden. Email not provided by provider or permission denied."
}
User Profile
Get Current User
GET /api/v1/auth/users/me/
Headers:
Authorization: Bearer <access_token>
Response (200 OK):
{
"id": 1,
"email": "user@example.com",
"first_name": "Ali",
"last_name": "Veli",
"is_active": true,
"date_joined": "2025-12-12T21:30:00Z"
}
Update Current User
PATCH /api/v1/auth/users/me/
Request Body:
{
"first_name": "Ahmet",
"last_name": "Yılmaz"
}
Curl Example
curl -X GET http://localhost:8000/api/v1/auth/users/me/ \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Password Reset
1. Request Password Reset
POST /api/v1/auth/users/reset_password/
Request Body:
{
"email": "user@example.com"
}
Response (204 No Content)
Email gönderilir, link formatı:
http://localhost:3000/auth/password/reset/confirm/{uid}/{token}/
2. Confirm Password Reset
POST /api/v1/auth/users/reset_password_confirm/
Request Body:
{
"uid": "MQ",
"token": "c4h7vu-a8f3d2e1c4b5a6d7e8f9g0h1",
"new_password": "NewStrongP@ssw0rd123",
"re_new_password": "NewStrongP@ssw0rd123"
}
Response (204 No Content)
Frontend Entegrasyonu
Nuxt.js 3 Example
1. Composable: useAuth.ts
// composables/useAuth.ts
export const useAuth = () => {
const config = useRuntimeConfig();
const accessToken = useCookie('access_token');
const refreshToken = useCookie('refresh_token');
const register = async (userData: {
email: string;
password: string;
re_password: string;
first_name: string;
last_name: string;
}) => {
const { data, error } = await useFetch(`${config.public.apiBase}/auth/users/`, {
method: 'POST',
body: userData,
});
return { data, error };
};
const login = async (email: string, password: string) => {
const { data, error } = await useFetch(`${config.public.apiBase}/auth/jwt/create/`, {
method: 'POST',
body: { email, password },
});
if (data.value) {
accessToken.value = data.value.access;
refreshToken.value = data.value.refresh;
}
return { data, error };
};
const socialLogin = async (provider: string, accessTokenValue: string) => {
const { data, error } = await useFetch(
`${config.public.apiBase}/auth/social/${provider}/`,
{
method: 'POST',
body: { access_token: accessTokenValue },
}
);
if (data.value) {
accessToken.value = data.value.access;
refreshToken.value = data.value.refresh;
}
return { data, error };
};
const getUser = async () => {
if (!accessToken.value) return null;
const { data } = await useFetch(`${config.public.apiBase}/auth/users/me/`, {
headers: {
Authorization: `Bearer ${accessToken.value}`,
},
});
return data.value;
};
const logout = () => {
accessToken.value = null;
refreshToken.value = null;
};
return {
register,
login,
socialLogin,
getUser,
logout,
accessToken,
refreshToken,
};
};
2. Register Page: pages/auth/register.vue
<template>
<div>
<h1>Register</h1>
<form @submit.prevent="handleRegister">
<input v-model="form.email" type="email" placeholder="Email" required />
<input v-model="form.first_name" placeholder="First Name" />
<input v-model="form.last_name" placeholder="Last Name" />
<input v-model="form.password" type="password" placeholder="Password" required />
<input v-model="form.re_password" type="password" placeholder="Confirm Password" required />
<button type="submit">Register</button>
</form>
<p v-if="message">{{ message }}</p>
</div>
</template>
<script setup lang="ts">
const { register } = useAuth();
const form = ref({
email: '',
password: '',
re_password: '',
first_name: '',
last_name: '',
});
const message = ref('');
const handleRegister = async () => {
const { data, error } = await register(form.value);
if (error.value) {
message.value = 'Registration failed';
} else {
message.value = 'Registration successful! Please check your email to activate your account.';
}
};
</script>
3. Activation Page: pages/auth/activate/[uid]/[token].vue
<template>
<div>
<h1>Account Activation</h1>
<p v-if="loading">Activating your account...</p>
<p v-else-if="success">✅ Account activated successfully! You can now login.</p>
<p v-else-if="error">❌ Activation failed. Link may be expired.</p>
</div>
</template>
<script setup lang="ts">
const route = useRoute();
const config = useRuntimeConfig();
const loading = ref(true);
const success = ref(false);
const error = ref(false);
onMounted(async () => {
const { uid, token } = route.params;
try {
await $fetch(`${config.public.apiBase}/auth/users/activation/`, {
method: 'POST',
body: { uid, token },
});
success.value = true;
} catch (e) {
error.value = true;
} finally {
loading.value = false;
}
});
</script>
4. Login Page: pages/auth/login.vue
<template>
<div>
<h1>Login</h1>
<form @submit.prevent="handleLogin">
<input v-model="email" type="email" placeholder="Email" required />
<input v-model="password" type="password" placeholder="Password" required />
<button type="submit">Login</button>
</form>
<div class="social-login">
<button @click="handleGoogleLogin">Login with Google</button>
<button @click="handleGithubLogin">Login with GitHub</button>
</div>
<p v-if="error">{{ error }}</p>
</div>
</template>
<script setup lang="ts">
const { login, socialLogin } = useAuth();
const router = useRouter();
const email = ref('');
const password = ref('');
const error = ref('');
const handleLogin = async () => {
const { data, error: loginError } = await login(email.value, password.value);
if (loginError.value) {
error.value = 'Login failed. Please check your credentials.';
} else {
router.push('/dashboard');
}
};
const handleGoogleLogin = async () => {
// Google OAuth2 implementation
// Use @nuxtjs/google-oauth2 or similar
const googleToken = await getGoogleAccessToken(); // Your implementation
const { data, error: socialError } = await socialLogin('google-oauth2', googleToken);
if (!socialError.value) {
router.push('/dashboard');
}
};
const handleGithubLogin = async () => {
// GitHub OAuth2 implementation
const githubToken = await getGithubAccessToken(); // Your implementation
const { data, error: socialError } = await socialLogin('github', githubToken);
if (!socialError.value) {
router.push('/dashboard');
}
};
</script>
Next.js 14 Example
1. Auth Context: context/AuthContext.tsx
'use client';
import { createContext, useContext, useState, useEffect } from 'react';
interface User {
id: number;
email: string;
first_name: string;
last_name: string;
}
interface AuthContextType {
user: User | null;
login: (email: string, password: string) => Promise<void>;
logout: () => void;
register: (userData: any) => Promise<void>;
}
const AuthContext = createContext<AuthContextType | undefined>(undefined);
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [accessToken, setAccessToken] = useState<string | null>(null);
useEffect(() => {
// Load token from localStorage
const token = localStorage.getItem('access_token');
if (token) {
setAccessToken(token);
fetchUser(token);
}
}, []);
const fetchUser = async (token: string) => {
try {
const response = await fetch('http://localhost:8000/api/v1/auth/users/me/', {
headers: {
'Authorization': `Bearer ${token}`,
},
});
const data = await response.json();
setUser(data);
} catch (error) {
console.error('Failed to fetch user', error);
}
};
const login = async (email: string, password: string) => {
const response = await fetch('http://localhost:8000/api/v1/auth/jwt/create/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, password }),
});
if (!response.ok) {
throw new Error('Login failed');
}
const data = await response.json();
localStorage.setItem('access_token', data.access);
localStorage.setItem('refresh_token', data.refresh);
setAccessToken(data.access);
await fetchUser(data.access);
};
const logout = () => {
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
setAccessToken(null);
setUser(null);
};
const register = async (userData: any) => {
const response = await fetch('http://localhost:8000/api/v1/auth/users/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData),
});
if (!response.ok) {
throw new Error('Registration failed');
}
};
return (
<AuthContext.Provider value={{ user, login, logout, register }}>
{children}
</AuthContext.Provider>
);
}
export const useAuth = () => {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
};
Error Handling
Common Error Codes
| Status Code | Meaning | Common Causes |
|---|---|---|
| 400 | Bad Request | Invalid data, validation errors |
| 401 | Unauthorized | Invalid credentials, expired token |
| 403 | Forbidden | Account not activated, permission denied |
| 404 | Not Found | Endpoint doesn't exist |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server-side error |
Error Response Format
{
"detail": "Error message here",
"field_name": ["Field-specific error"]
}
Example: Registration Validation Error
{
"email": ["A user with that email already exists."],
"password": ["This password is too common."]
}
Testing with Postman/Insomnia
1. Register
POST http://localhost:8000/api/v1/auth/users/
Content-Type: application/json
{
"email": "test@example.com",
"password": "TestP@ssw0rd123",
"re_password": "TestP@ssw0rd123",
"first_name": "Test",
"last_name": "User"
}
2. Check Email (MailPit)
Open: http://localhost:8025
3. Activate Account
POST http://localhost:8000/api/v1/auth/users/activation/
Content-Type: application/json
{
"uid": "MQ",
"token": "c4h7vu-a8f3d2e1c4b5a6d7e8f9g0h1"
}
4. Login
POST http://localhost:8000/api/v1/auth/jwt/create/
Content-Type: application/json
{
"email": "test@example.com",
"password": "TestP@ssw0rd123"
}
5. Get User Profile
GET http://localhost:8000/api/v1/auth/users/me/
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Environment Variables
Development (.env.dev)
DEBUG=True
SECRET_KEY=your-secret-key-here
ALLOWED_HOSTS=localhost,127.0.0.1
# Database
DATABASE_URL=sqlite:///db.sqlite3
# Email (MailPit)
EMAIL_HOST=localhost
EMAIL_PORT=1025
EMAIL_USE_TLS=False
# CORS
CORS_ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173
Production (.env.prod)
DEBUG=False
SECRET_KEY=your-production-secret-key
ALLOWED_HOSTS=yourdomain.com,api.yourdomain.com
# Database
DATABASE_URL=postgresql://user:pass@host:5432/dbname
# Email
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_HOST_USER=your-email@gmail.com
EMAIL_HOST_PASSWORD=your-app-password
# Social Auth
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY=your-google-client-id
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET=your-google-client-secret
SOCIAL_AUTH_GITHUB_KEY=your-github-client-id
SOCIAL_AUTH_GITHUB_SECRET=your-github-client-secret
# CORS
CORS_ALLOWED_ORIGINS=https://yourdomain.com
Support
Sorularınız için:
- GitHub Issues: [Your Repo]
- Email: support@yourdomain.com
- Documentation: [Your Docs URL]
Last Updated: 2025-12-12 Version: 1.0.0