fix: decode OAuth token response directly, not via FeishuAPIResponse wrapper

The /authen/v1/oidc/access_token and refresh_access_token endpoints return
token fields (access_token, refresh_token, expires_in) at the top level
of the JSON response, not nested under a 'data' key like standard Feishu
API responses. This caused 'Feishu API error (0): ok' — code 0 with no
wrapped data.

Changed exchangeCode and refreshAccessToken to decode OAuthTokenData
directly from the response. Removed unused decodeAPIResponse helper.

Also removed redirect_uri from token exchange body (not required by
Feishu's token endpoint).

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
tigerenwork 2026-06-29 00:13:48 +08:00
parent 74baa22d27
commit cf9de54792
1 changed files with 6 additions and 13 deletions

View File

@ -51,9 +51,9 @@ final class FeishuAuthService {
request.httpBody = try JSONEncoder().encode([
"grant_type": "authorization_code",
"code": code,
"redirect_uri": redirectURI,
] as [String: String])
return try await decodeAPIResponse(request)
// Token endpoints return data at top level, not wrapped in {code, msg, data}
return try await send(request)
}
func refreshAccessToken(_ refreshToken: String) async throws -> OAuthTokenData {
@ -65,9 +65,10 @@ final class FeishuAuthService {
request.setValue("Bearer \(tenantToken)", forHTTPHeaderField: "Authorization")
request.httpBody = try JSONEncoder().encode([
"grant_type": "refresh_token",
"refresh_token": refreshToken
])
return try await decodeAPIResponse(request)
"refresh_token": refreshToken,
] as [String: String])
// Token endpoints return data at top level, not wrapped in {code, msg, data}
return try await send(request)
}
func fetchCurrentUserName(accessToken: String) async throws -> String {
@ -112,14 +113,6 @@ final class FeishuAuthService {
return data.tenantAccessToken
}
private func decodeAPIResponse<T: Decodable>(_ request: URLRequest) async throws -> T {
let response: FeishuAPIResponse<T> = try await send(request)
guard response.code == 0, let data = response.data else {
throw FeishuError.apiError(code: response.code, message: response.msg)
}
return data
}
private func send<T: Decodable>(_ request: URLRequest) async throws -> T {
let (data, response) = try await session.data(for: request)
guard let httpResponse = response as? HTTPURLResponse else {