curl -X POST "https://api.tktchurch.com/v1/auth/link-provider" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"idToken": "eyJhbGciOiJSUzI1NiIs..."
}'
const linkProvider = async (accessToken, idToken) => {
const response = await fetch(
'https://api.tktchurch.com/v1/auth/link-provider',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ idToken })
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.reason);
}
return response.status === 200;
};
// Usage
try {
await linkProvider(
'eyJhbGciOiJIUzI1NiIs...', // access token
'eyJhbGciOiJSUzI1NiIs...' // ID token from provider
);
console.log('Provider linked successfully');
} catch (error) {
console.error('Failed to link provider:', error.message);
}
func linkProvider(accessToken: String, idToken: String) async throws {
var urlRequest = URLRequest(url: URL(string: "https://api.tktchurch.com/v1/auth/link-provider")!)
urlRequest.httpMethod = "POST"
urlRequest.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body = ["idToken": idToken]
urlRequest.httpBody = try JSONEncoder().encode(body)
let (_, response) = try await URLSession.shared.data(for: urlRequest)
guard let httpResponse = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
if httpResponse.statusCode != 200 {
throw URLError(.badServerResponse)
}
}
// Usage
do {
try await linkProvider(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
idToken: "eyJhbGciOiJSUzI1NiIs..."
)
print("Provider linked successfully")
} catch {
print("Failed to link provider: \(error.localizedDescription)")
}
class UserService(private val client: OkHttpClient) {
suspend fun linkProvider(accessToken: String, idToken: String) {
val requestBody = """
{
"idToken": "$idToken"
}
""".trimIndent()
val request = Request.Builder()
.url("https://api.tktchurch.com/v1/auth/link-provider")
.post(RequestBody.create(MediaType.parse("application/json"), requestBody))
.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 link provider")
}
}
}
}
// Usage
try {
userService.linkProvider(
"eyJhbGciOiJIUzI1NiIs...", // access token
"eyJhbGciOiJSUzI1NiIs..." // ID token from provider
)
println("Provider linked successfully")
} catch (e: Exception) {
println("Failed to link provider: ${e.message}")
}
import axios from 'axios';
const linkProvider = async (accessToken: string, idToken: string): Promise<void> => {
try {
await axios.post(
'https://api.tktchurch.com/v1/auth/link-provider',
{ idToken },
{
headers: {
'Authorization': `Bearer ${accessToken}`
},
}
);
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.error?.reason || 'Failed to link provider');
}
throw error;
}
};
// Usage
try {
await linkProvider(
'eyJhbGciOiJIUzI1NiIs...', // access token
'eyJhbGciOiJSUzI1NiIs...' // ID token from provider
);
console.log('Provider linked successfully');
} catch (error) {
console.error('Failed to link provider:', error.message);
}
{
"error": {
"status": 400,
"reason": "Email mismatch"
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 409,
"reason": "Provider already linked to another account"
}
}
Authentication
Link Provider
Link a new authentication provider to the current account
POST
/
auth
/
link-provider
curl -X POST "https://api.tktchurch.com/v1/auth/link-provider" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"idToken": "eyJhbGciOiJSUzI1NiIs..."
}'
const linkProvider = async (accessToken, idToken) => {
const response = await fetch(
'https://api.tktchurch.com/v1/auth/link-provider',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ idToken })
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.reason);
}
return response.status === 200;
};
// Usage
try {
await linkProvider(
'eyJhbGciOiJIUzI1NiIs...', // access token
'eyJhbGciOiJSUzI1NiIs...' // ID token from provider
);
console.log('Provider linked successfully');
} catch (error) {
console.error('Failed to link provider:', error.message);
}
func linkProvider(accessToken: String, idToken: String) async throws {
var urlRequest = URLRequest(url: URL(string: "https://api.tktchurch.com/v1/auth/link-provider")!)
urlRequest.httpMethod = "POST"
urlRequest.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body = ["idToken": idToken]
urlRequest.httpBody = try JSONEncoder().encode(body)
let (_, response) = try await URLSession.shared.data(for: urlRequest)
guard let httpResponse = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
if httpResponse.statusCode != 200 {
throw URLError(.badServerResponse)
}
}
// Usage
do {
try await linkProvider(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
idToken: "eyJhbGciOiJSUzI1NiIs..."
)
print("Provider linked successfully")
} catch {
print("Failed to link provider: \(error.localizedDescription)")
}
class UserService(private val client: OkHttpClient) {
suspend fun linkProvider(accessToken: String, idToken: String) {
val requestBody = """
{
"idToken": "$idToken"
}
""".trimIndent()
val request = Request.Builder()
.url("https://api.tktchurch.com/v1/auth/link-provider")
.post(RequestBody.create(MediaType.parse("application/json"), requestBody))
.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 link provider")
}
}
}
}
// Usage
try {
userService.linkProvider(
"eyJhbGciOiJIUzI1NiIs...", // access token
"eyJhbGciOiJSUzI1NiIs..." // ID token from provider
)
println("Provider linked successfully")
} catch (e: Exception) {
println("Failed to link provider: ${e.message}")
}
import axios from 'axios';
const linkProvider = async (accessToken: string, idToken: string): Promise<void> => {
try {
await axios.post(
'https://api.tktchurch.com/v1/auth/link-provider',
{ idToken },
{
headers: {
'Authorization': `Bearer ${accessToken}`
},
}
);
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.error?.reason || 'Failed to link provider');
}
throw error;
}
};
// Usage
try {
await linkProvider(
'eyJhbGciOiJIUzI1NiIs...', // access token
'eyJhbGciOiJSUzI1NiIs...' // ID token from provider
);
console.log('Provider linked successfully');
} catch (error) {
console.error('Failed to link provider:', error.message);
}
{
"error": {
"status": 400,
"reason": "Email mismatch"
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 409,
"reason": "Provider already linked to another account"
}
}
This endpoint requires authentication.
Request Body
string
required
The ID token obtained from the provider (Google, Apple, or Facebook)
Response
A successful request returns HTTP 200 OK status. The provider is linked to the current user’s account.Error Responses
object
Common error cases:
- 400 Bad Request: Invalid or missing ID token
- 400 Bad Request: Email mismatch between accounts
- 400 Bad Request: Provider already linked to this account
- 401 Unauthorized: Missing or invalid access token
- 409 Conflict: Provider already linked to another account
curl -X POST "https://api.tktchurch.com/v1/auth/link-provider" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"idToken": "eyJhbGciOiJSUzI1NiIs..."
}'
const linkProvider = async (accessToken, idToken) => {
const response = await fetch(
'https://api.tktchurch.com/v1/auth/link-provider',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ idToken })
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error.reason);
}
return response.status === 200;
};
// Usage
try {
await linkProvider(
'eyJhbGciOiJIUzI1NiIs...', // access token
'eyJhbGciOiJSUzI1NiIs...' // ID token from provider
);
console.log('Provider linked successfully');
} catch (error) {
console.error('Failed to link provider:', error.message);
}
func linkProvider(accessToken: String, idToken: String) async throws {
var urlRequest = URLRequest(url: URL(string: "https://api.tktchurch.com/v1/auth/link-provider")!)
urlRequest.httpMethod = "POST"
urlRequest.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body = ["idToken": idToken]
urlRequest.httpBody = try JSONEncoder().encode(body)
let (_, response) = try await URLSession.shared.data(for: urlRequest)
guard let httpResponse = response as? HTTPURLResponse else {
throw URLError(.badServerResponse)
}
if httpResponse.statusCode != 200 {
throw URLError(.badServerResponse)
}
}
// Usage
do {
try await linkProvider(
accessToken: "eyJhbGciOiJIUzI1NiIs...",
idToken: "eyJhbGciOiJSUzI1NiIs..."
)
print("Provider linked successfully")
} catch {
print("Failed to link provider: \(error.localizedDescription)")
}
class UserService(private val client: OkHttpClient) {
suspend fun linkProvider(accessToken: String, idToken: String) {
val requestBody = """
{
"idToken": "$idToken"
}
""".trimIndent()
val request = Request.Builder()
.url("https://api.tktchurch.com/v1/auth/link-provider")
.post(RequestBody.create(MediaType.parse("application/json"), requestBody))
.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 link provider")
}
}
}
}
// Usage
try {
userService.linkProvider(
"eyJhbGciOiJIUzI1NiIs...", // access token
"eyJhbGciOiJSUzI1NiIs..." // ID token from provider
)
println("Provider linked successfully")
} catch (e: Exception) {
println("Failed to link provider: ${e.message}")
}
import axios from 'axios';
const linkProvider = async (accessToken: string, idToken: string): Promise<void> => {
try {
await axios.post(
'https://api.tktchurch.com/v1/auth/link-provider',
{ idToken },
{
headers: {
'Authorization': `Bearer ${accessToken}`
},
}
);
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(error.response?.data?.error?.reason || 'Failed to link provider');
}
throw error;
}
};
// Usage
try {
await linkProvider(
'eyJhbGciOiJIUzI1NiIs...', // access token
'eyJhbGciOiJSUzI1NiIs...' // ID token from provider
);
console.log('Provider linked successfully');
} catch (error) {
console.error('Failed to link provider:', error.message);
}
{
"error": {
"status": 400,
"reason": "Email mismatch"
}
}
{
"error": {
"status": 401,
"reason": "Invalid or expired access token"
}
}
{
"error": {
"status": 409,
"reason": "Provider already linked to another account"
}
}
