curl -X DELETE "https://api.tktchurch.com/v1/devices/users/123e4567-e89b-12d3-a456-426614174000/456e789a-b12d-3456-789a-bcdef0123456" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
const revokeUserDevice = async (accessToken, userId, deviceId) => {
const response = await fetch(
`https://api.tktchurch.com/v1/devices/users/${userId}/${deviceId}`,
{
method: 'DELETE',
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.reason);
}
return response.status === 204;
};
// Usage
try {
await revokeUserDevice(
'eyJhbGciOiJIUzI1NiIs...', // access token
'123e4567-e89b-12d3-a456-426614174000', // user ID
'456e789a-b12d-3456-789a-bcdef0123456' // device ID
);
console.log('Device revoked successfully');
} catch (error) {
console.error('Failed to revoke device:', error.message);
}
func revokeUserDevice(accessToken: String, userId: UUID, deviceId: UUID) async throws {
var urlRequest = URLRequest(url: URL(string: "https://api.tktchurch.com/v1/devices/users/\(userId)/\(deviceId)")!)
urlRequest.httpMethod = "DELETE"
urlRequest.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
let (_, response) = try await URLSession.shared.data(for: urlRequest)
guard let httpResponse = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
if httpResponse.statusCode != 204 {
throw URLError(.badServerResponse)
}
}
// Usage
do {
try await revokeUserDevice(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
userId: UUID(uuidString: "123e4567-e89b-12d3-a456-426614174000")!,
deviceId: UUID(uuidString: "456e789a-b12d-3456-789a-bcdef0123456")!
)
print("Device revoked successfully")
} catch {
print("Failed to revoke device: \(error.localizedDescription)")
}
class DeviceService(private val client: OkHttpClient) {
suspend fun revokeUserDevice(accessToken: String, userId: String, deviceId: String) {
val request = Request.Builder()
.url("https://api.tktchurch.com/v1/devices/users/$userId/$deviceId")
.delete()
.header("Authorization", "Bearer $accessToken")
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
val error = response.body?.string()?.fromJson<ErrorResponse>()
throw Exception(error?.reason ?: "Failed to revoke device")
}
}
}
}
// Usage
try {
deviceService.revokeUserDevice(
"eyJhbGciOiJIUzI1NiIs...", // access token
"123e4567-e89b-12d3-a456-426614174000", // user ID
"456e789a-b12d-3456-789a-bcdef0123456" // device ID
)
println("Device revoked successfully")
} catch (e: Exception) {
println("Failed to revoke device: ${e.message}")
}
import axios from 'axios';
const revokeUserDevice = async (
accessToken: string,
userId: string,
deviceId: string
): Promise<void> => {
try {
await axios.delete(
`https://api.tktchurch.com/v1/devices/users/${userId}/${deviceId}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
},
}
);
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.error?.reason || 'Failed to revoke device');
}
throw error;
}
};
// Usage
try {
await revokeUserDevice(
'eyJhbGciOiJIUzI1NiIs...', // access token
'123e4567-e89b-12d3-a456-426614174000', // user ID
'456e789a-b12d-3456-789a-bcdef0123456' // device ID
);
console.log('Device revoked successfully');
} catch (error) {
console.error('Failed to revoke device:', error.message);
}
{
"error": {
"status": 400,
"reason": "Invalid user ID"
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 403,
"reason": "Insufficient permissions"
}
}
{
"error": {
"status": 404,
"reason": "User not found"
}
}
Devices
Revoke User Device
Revoke access for a specific device belonging to a user
DELETE
/
devices
/
users
/
{userId}
/
{deviceId}
curl -X DELETE "https://api.tktchurch.com/v1/devices/users/123e4567-e89b-12d3-a456-426614174000/456e789a-b12d-3456-789a-bcdef0123456" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
const revokeUserDevice = async (accessToken, userId, deviceId) => {
const response = await fetch(
`https://api.tktchurch.com/v1/devices/users/${userId}/${deviceId}`,
{
method: 'DELETE',
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.reason);
}
return response.status === 204;
};
// Usage
try {
await revokeUserDevice(
'eyJhbGciOiJIUzI1NiIs...', // access token
'123e4567-e89b-12d3-a456-426614174000', // user ID
'456e789a-b12d-3456-789a-bcdef0123456' // device ID
);
console.log('Device revoked successfully');
} catch (error) {
console.error('Failed to revoke device:', error.message);
}
func revokeUserDevice(accessToken: String, userId: UUID, deviceId: UUID) async throws {
var urlRequest = URLRequest(url: URL(string: "https://api.tktchurch.com/v1/devices/users/\(userId)/\(deviceId)")!)
urlRequest.httpMethod = "DELETE"
urlRequest.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
let (_, response) = try await URLSession.shared.data(for: urlRequest)
guard let httpResponse = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
if httpResponse.statusCode != 204 {
throw URLError(.badServerResponse)
}
}
// Usage
do {
try await revokeUserDevice(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
userId: UUID(uuidString: "123e4567-e89b-12d3-a456-426614174000")!,
deviceId: UUID(uuidString: "456e789a-b12d-3456-789a-bcdef0123456")!
)
print("Device revoked successfully")
} catch {
print("Failed to revoke device: \(error.localizedDescription)")
}
class DeviceService(private val client: OkHttpClient) {
suspend fun revokeUserDevice(accessToken: String, userId: String, deviceId: String) {
val request = Request.Builder()
.url("https://api.tktchurch.com/v1/devices/users/$userId/$deviceId")
.delete()
.header("Authorization", "Bearer $accessToken")
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
val error = response.body?.string()?.fromJson<ErrorResponse>()
throw Exception(error?.reason ?: "Failed to revoke device")
}
}
}
}
// Usage
try {
deviceService.revokeUserDevice(
"eyJhbGciOiJIUzI1NiIs...", // access token
"123e4567-e89b-12d3-a456-426614174000", // user ID
"456e789a-b12d-3456-789a-bcdef0123456" // device ID
)
println("Device revoked successfully")
} catch (e: Exception) {
println("Failed to revoke device: ${e.message}")
}
import axios from 'axios';
const revokeUserDevice = async (
accessToken: string,
userId: string,
deviceId: string
): Promise<void> => {
try {
await axios.delete(
`https://api.tktchurch.com/v1/devices/users/${userId}/${deviceId}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
},
}
);
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.error?.reason || 'Failed to revoke device');
}
throw error;
}
};
// Usage
try {
await revokeUserDevice(
'eyJhbGciOiJIUzI1NiIs...', // access token
'123e4567-e89b-12d3-a456-426614174000', // user ID
'456e789a-b12d-3456-789a-bcdef0123456' // device ID
);
console.log('Device revoked successfully');
} catch (error) {
console.error('Failed to revoke device:', error.message);
}
{
"error": {
"status": 400,
"reason": "Invalid user ID"
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 403,
"reason": "Insufficient permissions"
}
}
{
"error": {
"status": 404,
"reason": "User not found"
}
}
This endpoint requires authentication and the
viewUserDevices permission.Path Parameters
string
required
The UUID of the user whose device to revoke
string
required
The UUID of the device token to revoke
Response
A successful request returns HTTP 204 No Content status. The following actions are performed:- The device’s refresh token is blacklisted
- Any associated access tokens are blacklisted
- The tokens are removed from the database
Error Responses
object
Common error cases:
- 400 Bad Request: Invalid user ID or device ID format
- 401 Unauthorized: Missing or invalid access token
- 403 Forbidden: Insufficient permissions (missing viewUserDevices)
- 404 Not Found: User or device not found
curl -X DELETE "https://api.tktchurch.com/v1/devices/users/123e4567-e89b-12d3-a456-426614174000/456e789a-b12d-3456-789a-bcdef0123456" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
const revokeUserDevice = async (accessToken, userId, deviceId) => {
const response = await fetch(
`https://api.tktchurch.com/v1/devices/users/${userId}/${deviceId}`,
{
method: 'DELETE',
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.reason);
}
return response.status === 204;
};
// Usage
try {
await revokeUserDevice(
'eyJhbGciOiJIUzI1NiIs...', // access token
'123e4567-e89b-12d3-a456-426614174000', // user ID
'456e789a-b12d-3456-789a-bcdef0123456' // device ID
);
console.log('Device revoked successfully');
} catch (error) {
console.error('Failed to revoke device:', error.message);
}
func revokeUserDevice(accessToken: String, userId: UUID, deviceId: UUID) async throws {
var urlRequest = URLRequest(url: URL(string: "https://api.tktchurch.com/v1/devices/users/\(userId)/\(deviceId)")!)
urlRequest.httpMethod = "DELETE"
urlRequest.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
let (_, response) = try await URLSession.shared.data(for: urlRequest)
guard let httpResponse = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
if httpResponse.statusCode != 204 {
throw URLError(.badServerResponse)
}
}
// Usage
do {
try await revokeUserDevice(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
userId: UUID(uuidString: "123e4567-e89b-12d3-a456-426614174000")!,
deviceId: UUID(uuidString: "456e789a-b12d-3456-789a-bcdef0123456")!
)
print("Device revoked successfully")
} catch {
print("Failed to revoke device: \(error.localizedDescription)")
}
class DeviceService(private val client: OkHttpClient) {
suspend fun revokeUserDevice(accessToken: String, userId: String, deviceId: String) {
val request = Request.Builder()
.url("https://api.tktchurch.com/v1/devices/users/$userId/$deviceId")
.delete()
.header("Authorization", "Bearer $accessToken")
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
val error = response.body?.string()?.fromJson<ErrorResponse>()
throw Exception(error?.reason ?: "Failed to revoke device")
}
}
}
}
// Usage
try {
deviceService.revokeUserDevice(
"eyJhbGciOiJIUzI1NiIs...", // access token
"123e4567-e89b-12d3-a456-426614174000", // user ID
"456e789a-b12d-3456-789a-bcdef0123456" // device ID
)
println("Device revoked successfully")
} catch (e: Exception) {
println("Failed to revoke device: ${e.message}")
}
import axios from 'axios';
const revokeUserDevice = async (
accessToken: string,
userId: string,
deviceId: string
): Promise<void> => {
try {
await axios.delete(
`https://api.tktchurch.com/v1/devices/users/${userId}/${deviceId}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
},
}
);
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.error?.reason || 'Failed to revoke device');
}
throw error;
}
};
// Usage
try {
await revokeUserDevice(
'eyJhbGciOiJIUzI1NiIs...', // access token
'123e4567-e89b-12d3-a456-426614174000', // user ID
'456e789a-b12d-3456-789a-bcdef0123456' // device ID
);
console.log('Device revoked successfully');
} catch (error) {
console.error('Failed to revoke device:', error.message);
}
{
"error": {
"status": 400,
"reason": "Invalid user ID"
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 403,
"reason": "Insufficient permissions"
}
}
{
"error": {
"status": 404,
"reason": "User not found"
}
}
