curl -X POST "https://api.tktchurch.com/v1/auth/logout" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "eyJhbGciOiJIUzI1NiIs..."
}'
const logout = async (accessToken, refreshToken = null) => {
const response = await fetch('https://api.tktchurch.com/v1/auth/logout', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: refreshToken ? JSON.stringify({ refresh_token: refreshToken }) : undefined
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.reason);
}
return response.status === 204;
};
// Usage
try {
await logout(
'eyJhbGciOiJIUzI1NiIs...', // access token
'eyJhbGciOiJIUzI1NiIs...' // refresh token (optional)
);
console.log('Logged out successfully');
} catch (error) {
console.error('Failed to logout:', error.message);
}
func logout(accessToken: String, refreshToken: String? = nil) async throws {
var urlRequest = URLRequest(url: URL(string: "https://api.tktchurch.com/v1/auth/logout")!)
urlRequest.httpMethod = "POST"
urlRequest.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
if let refreshToken = refreshToken {
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body = ["refresh_token": refreshToken]
urlRequest.httpBody = try? JSONEncoder().encode(body)
}
let (data, response) = try await URLSession.shared.data(for: urlRequest)
guard let httpResponse = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
if httpResponse.statusCode != 204 {
let error = try JSONDecoder().decode(ErrorResponse.self, from: data)
throw error
}
}
// Usage
do {
try await logout(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
refreshToken: "eyJhbGciOiJIUzI1NiIs..." // optional
)
print("Logged out successfully")
} catch {
print("Failed to logout: \(error.localizedDescription)")
}
class AuthService(private val client: OkHttpClient) {
suspend fun logout(accessToken: String, refreshToken: String? = null) {
val requestBody = refreshToken?.let {
mapOf("refresh_token" to it).toJson()
.toRequestBody("application/json".toMediaType())
}
val request = Request.Builder()
.url("https://api.tktchurch.com/v1/auth/logout")
.post(requestBody ?: "".toRequestBody())
.header("Authorization", "Bearer $accessToken")
.apply {
refreshToken?.let {
header("Content-Type", "application/json")
}
}
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
val error = response.body?.string()?.fromJson<ErrorResponse>()
throw Exception(error?.reason ?: "Failed to logout")
}
}
}
}
// Usage
try {
authService.logout(
"eyJhbGciOiJIUzI1NiIs...", // access token
"eyJhbGciOiJIUzI1NiIs..." // refresh token (optional)
)
println("Logged out successfully")
} catch (e: Exception) {
println("Failed to logout: ${e.message}")
}
import axios from 'axios';
interface LogoutRequest {
refresh_token?: string;
}
const logout = async (accessToken: string, refreshToken?: string): Promise<boolean> => {
try {
const response = await axios.post(
'https://api.tktchurch.com/v1/auth/logout',
refreshToken ? { refresh_token: refreshToken } : undefined,
{
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
}
);
return response.status === 204;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.error?.reason || 'Failed to logout');
}
throw error;
}
};
// Usage
try {
await logout(
'eyJhbGciOiJIUzI1NiIs...', // access token
'eyJhbGciOiJIUzI1NiIs...' // refresh token (optional)
);
console.log('Logged out successfully');
} catch (error) {
console.error('Failed to logout:', error.message);
}
// No content
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 404,
"reason": "User not found"
}
}
Authentication
Logout
Revoke access and refresh tokens, invalidating the current session
POST
/
auth
/
logout
curl -X POST "https://api.tktchurch.com/v1/auth/logout" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "eyJhbGciOiJIUzI1NiIs..."
}'
const logout = async (accessToken, refreshToken = null) => {
const response = await fetch('https://api.tktchurch.com/v1/auth/logout', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: refreshToken ? JSON.stringify({ refresh_token: refreshToken }) : undefined
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.reason);
}
return response.status === 204;
};
// Usage
try {
await logout(
'eyJhbGciOiJIUzI1NiIs...', // access token
'eyJhbGciOiJIUzI1NiIs...' // refresh token (optional)
);
console.log('Logged out successfully');
} catch (error) {
console.error('Failed to logout:', error.message);
}
func logout(accessToken: String, refreshToken: String? = nil) async throws {
var urlRequest = URLRequest(url: URL(string: "https://api.tktchurch.com/v1/auth/logout")!)
urlRequest.httpMethod = "POST"
urlRequest.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
if let refreshToken = refreshToken {
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body = ["refresh_token": refreshToken]
urlRequest.httpBody = try? JSONEncoder().encode(body)
}
let (data, response) = try await URLSession.shared.data(for: urlRequest)
guard let httpResponse = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
if httpResponse.statusCode != 204 {
let error = try JSONDecoder().decode(ErrorResponse.self, from: data)
throw error
}
}
// Usage
do {
try await logout(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
refreshToken: "eyJhbGciOiJIUzI1NiIs..." // optional
)
print("Logged out successfully")
} catch {
print("Failed to logout: \(error.localizedDescription)")
}
class AuthService(private val client: OkHttpClient) {
suspend fun logout(accessToken: String, refreshToken: String? = null) {
val requestBody = refreshToken?.let {
mapOf("refresh_token" to it).toJson()
.toRequestBody("application/json".toMediaType())
}
val request = Request.Builder()
.url("https://api.tktchurch.com/v1/auth/logout")
.post(requestBody ?: "".toRequestBody())
.header("Authorization", "Bearer $accessToken")
.apply {
refreshToken?.let {
header("Content-Type", "application/json")
}
}
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
val error = response.body?.string()?.fromJson<ErrorResponse>()
throw Exception(error?.reason ?: "Failed to logout")
}
}
}
}
// Usage
try {
authService.logout(
"eyJhbGciOiJIUzI1NiIs...", // access token
"eyJhbGciOiJIUzI1NiIs..." // refresh token (optional)
)
println("Logged out successfully")
} catch (e: Exception) {
println("Failed to logout: ${e.message}")
}
import axios from 'axios';
interface LogoutRequest {
refresh_token?: string;
}
const logout = async (accessToken: string, refreshToken?: string): Promise<boolean> => {
try {
const response = await axios.post(
'https://api.tktchurch.com/v1/auth/logout',
refreshToken ? { refresh_token: refreshToken } : undefined,
{
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
}
);
return response.status === 204;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.error?.reason || 'Failed to logout');
}
throw error;
}
};
// Usage
try {
await logout(
'eyJhbGciOiJIUzI1NiIs...', // access token
'eyJhbGciOiJIUzI1NiIs...' // refresh token (optional)
);
console.log('Logged out successfully');
} catch (error) {
console.error('Failed to logout:', error.message);
}
// No content
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 404,
"reason": "User not found"
}
}
This endpoint requires authentication. Include the JWT access token in the Authorization header.
Request Body
string
Optional refresh token to revoke. If provided, both access and refresh tokens will be blacklisted.
Response
A successful request returns HTTP 204 No Content status. The following actions are performed:- The current access token is blacklisted
- The refresh token is blacklisted (if provided)
- The user’s
validSincetimestamp is updated, invalidating all previous tokens - Expired blacklisted tokens are cleaned up from the database
Error Responses
object
Common error cases:
- 401 Unauthorized: Missing or invalid access token
- 401 Unauthorized: Token has expired
- 404 Not Found: User not found
curl -X POST "https://api.tktchurch.com/v1/auth/logout" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "eyJhbGciOiJIUzI1NiIs..."
}'
const logout = async (accessToken, refreshToken = null) => {
const response = await fetch('https://api.tktchurch.com/v1/auth/logout', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: refreshToken ? JSON.stringify({ refresh_token: refreshToken }) : undefined
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.reason);
}
return response.status === 204;
};
// Usage
try {
await logout(
'eyJhbGciOiJIUzI1NiIs...', // access token
'eyJhbGciOiJIUzI1NiIs...' // refresh token (optional)
);
console.log('Logged out successfully');
} catch (error) {
console.error('Failed to logout:', error.message);
}
func logout(accessToken: String, refreshToken: String? = nil) async throws {
var urlRequest = URLRequest(url: URL(string: "https://api.tktchurch.com/v1/auth/logout")!)
urlRequest.httpMethod = "POST"
urlRequest.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
if let refreshToken = refreshToken {
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body = ["refresh_token": refreshToken]
urlRequest.httpBody = try? JSONEncoder().encode(body)
}
let (data, response) = try await URLSession.shared.data(for: urlRequest)
guard let httpResponse = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
if httpResponse.statusCode != 204 {
let error = try JSONDecoder().decode(ErrorResponse.self, from: data)
throw error
}
}
// Usage
do {
try await logout(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
refreshToken: "eyJhbGciOiJIUzI1NiIs..." // optional
)
print("Logged out successfully")
} catch {
print("Failed to logout: \(error.localizedDescription)")
}
class AuthService(private val client: OkHttpClient) {
suspend fun logout(accessToken: String, refreshToken: String? = null) {
val requestBody = refreshToken?.let {
mapOf("refresh_token" to it).toJson()
.toRequestBody("application/json".toMediaType())
}
val request = Request.Builder()
.url("https://api.tktchurch.com/v1/auth/logout")
.post(requestBody ?: "".toRequestBody())
.header("Authorization", "Bearer $accessToken")
.apply {
refreshToken?.let {
header("Content-Type", "application/json")
}
}
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
val error = response.body?.string()?.fromJson<ErrorResponse>()
throw Exception(error?.reason ?: "Failed to logout")
}
}
}
}
// Usage
try {
authService.logout(
"eyJhbGciOiJIUzI1NiIs...", // access token
"eyJhbGciOiJIUzI1NiIs..." // refresh token (optional)
)
println("Logged out successfully")
} catch (e: Exception) {
println("Failed to logout: ${e.message}")
}
import axios from 'axios';
interface LogoutRequest {
refresh_token?: string;
}
const logout = async (accessToken: string, refreshToken?: string): Promise<boolean> => {
try {
const response = await axios.post(
'https://api.tktchurch.com/v1/auth/logout',
refreshToken ? { refresh_token: refreshToken } : undefined,
{
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
}
);
return response.status === 204;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.error?.reason || 'Failed to logout');
}
throw error;
}
};
// Usage
try {
await logout(
'eyJhbGciOiJIUzI1NiIs...', // access token
'eyJhbGciOiJIUzI1NiIs...' // refresh token (optional)
);
console.log('Logged out successfully');
} catch (error) {
console.error('Failed to logout:', error.message);
}
// No content
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 404,
"reason": "User not found"
}
}
