Alur otorisasi PKCE Spotify menampilkan "code_verifier salah"
Saya telah mengikuti Panduan Otentikasi API Spotify untuk mengautentikasi aplikasi saya menggunakan PKCE.
Saat ini, saya menggunakan pemverifikasi kode dummy dengan tantangan yang telah dihitung sebelumnya untuk debugging. Nilai-nilai ini dihitung menggunakan beberapa alat online ( SHA256 , SHA256 , base64url , base64url ) dan cocok dengan nilai yang dikembalikan dari fungsi hashing / encoding yang saya tulis di Swift. Silakan gunakan tautan di atas untuk memverifikasi ini.
let verifier = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
let challenge = "66d34fba71f8f450f7e45598853e53bfc23bbd129027cbb131a2f4ffd7878cd0"
let challengeBase64URL = "NjZkMzRmYmE3MWY4ZjQ1MGY3ZTQ1NTk4ODUzZTUzYmZjMjNiYmQxMjkwMjdjYmIxMzFhMmY0ZmZkNzg3OGNkMA"
Saya menggunakan ASWebAuthenticationSession untuk membuat permintaan awal saya pada langkah 2, seperti:
var components = URLComponents()
components.scheme = "https"
components.host = "accounts.spotify.com"
components.path = "/authorize"
components.queryItems = [
URLQueryItem(name: "client_id", value: SpotifyClientID),
URLQueryItem(name: "response_type", value: "code"),
URLQueryItem(name: "redirect_uri", value: SpotifyRedirectURL.absoluteString),
URLQueryItem(name: "code_challenge_method", value: "S256"),
URLQueryItem(name: "code_challenge", value: challenge),
URLQueryItem(name: "state", value: "testing-state"),
URLQueryItem(name: "scope", value: "user-follow-read")
]
let urlString = components.url!.absoluteString
guard let authURL = URL(string: urlString) else { return }
print(authURL)
let authSession = ASWebAuthenticationSession(url: authURL, callbackURLScheme: callbackScheme, completionHandler: handleLoginResponse)
authSession.presentationContextProvider = self
authSession.prefersEphemeralWebBrowserSession = true
authSession.start()
Di handleLoginResponse
, saya mengurai respons di langkah 3 dan membuat permintaan jaringan untuk langkah 4 menggunakan Alamofire:
guard let items = URLComponents(string: callbackURL?.absoluteString ?? "").queryItems else { return }
let authCode = items[0].value!
let endpoint = "https://accounts.spotify.com/api/token"
let headers = HTTPHeaders(["Content-Type": "application/x-www-form-urlencoded"])
let parameters: [String: String] = [
"client_id": SpotifyClientID,
"grant_type": "authorization_code",
"code": authCode,
"redirect_uri": SpotifyRedirectURL.absoluteString,
"code_verifier": verifier!
]
AF.request(endpoint,
method: .post,
parameters: parameters,
encoder: URLEncodedFormParameterEncoder.default,
headers: headers
).cURLDescription() { description in
print(description)
}
.responseJSON() { (json) in
print(json)
}
Alamofire membuat antarmuka untuk membuat permintaan cURL dari dalam Swift, dan panggilan cURLDescription()
memungkinkan saya untuk melihat dengan tepat seperti apa sebenarnya perintah cURL itu:
$ curl -v \
-X POST \
-b "__Host-device_id=AQBHyRKdulrPJU6vY5xlua1xKOZBtBZVcrW9IK-X0LQ_MPj5x3N4mZkF4OzgLMdQwviWUxJ2dY6d49d0QpjG0ayFtCfrhwzG5-g" \
-H "User-Agent: SpotifyUserGraph/1.0 (hl999.SpotifyUserGraph; build:1; iOS 14.0.0) Alamofire/5.1.0" \
-H "Accept-Encoding: br;q=1.0, gzip;q=0.9, deflate;q=0.8" \
-H "Accept-Language: en-US;q=1.0, zh-Hans-US;q=0.9, ko-US;q=0.8" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=e11fb810282946569aab8f89e52f78d5&code=AQC3Lm3KDPFCg3mBjSAiXMyvjdn5GvUJCjjCTQzPhAFe5mLntAHcAeiEufXcCv3Jne2qn345MZxBNiCggO-35mn6AAFsjRlm5lPynyC6clWABSzBK1OdWIynTlf0CiyR8vWYeO54GHHEXBSzj6URKWnAiXuxTUV6n1Axra6Oet8FY6-0jwU0CNGMaB91q1JFXlyl5J9JvrRtrP3s2Ef8Xb5A7gcCzqW6RHRzO0--BKiPHFnprK0SitiLxi-md2aaMnS2aHsRTqvc_NfFcuRpFR05WmSm6Gvkk_9trSBqRvVZYuGs-Ap3-ydVGk7BCqNc3lpbh4Jku6W_930fOg9kI__zRA&code_verifier=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&grant_type=authorization_code&redirect_uri=hl999-spotifyusergraph%3A//spotify-login-callback" \
"https://accounts.spotify.com/api/token"
Agak sulit untuk dibaca, tetapi saya cukup yakin permintaan tersebut dibuat dengan benar.
Namun, pada langkah 4, saya selalu menerima pesan kesalahan ini dari server:
error = "invalid_grant";
"error_description" = "code_verifier was incorrect";
Saya sudah mencoba banyak hal selama beberapa jam dan masih belum bisa memahaminya. Setiap petunjuk akan sangat dihargai. Terima kasih!
Jawaban
Masalah Anda adalah bahwa byte mentah dari hash SHA adalah yang perlu menjadi base64. Saya juga mengerjakan aplikasi yang menggunakan Alamofire dan Spotify PKCE serta mengalami masalah dengan tantangan kode. Apa yang saya lakukan adalah menggunakan beberapa kode dari dokumentasi Auth0 yang ditulis untuk Swift 3 dan memodifikasinya agar berfungsi dengan Swift 5:
import Foundation
import CommonCrypto
func challenge(verifier: String) -> String {
guard let verifierData = verifier.data(using: String.Encoding.utf8) else { return "error" }
var buffer = [UInt8](repeating: 0, count:Int(CC_SHA256_DIGEST_LENGTH))
verifierData.withUnsafeBytes {
CC_SHA256($0.baseAddress, CC_LONG(verifierData.count), &buffer)
}
let hash = Data(_: buffer)
print(hash)
let challenge = hash.base64EncodedData()
return String(decoding: challenge, as: UTF8.self)
.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
.replacingOccurrences(of: "=", with: "")
.trimmingCharacters(in: .whitespaces)
}
print(challenge(verifier: "ExampleVerifier"))
Semoga ini membantu dan semoga sukses untuk Anda!
Ketika saya menggunakan verifikator PKCE online ini, saya mendapat tantangan berbeda untuk verifikator jadi saya mungkin akan mencoba lagi dengan nilai yang diberikan alat itu kepada Anda.
KEAMANAN SECARA KESELURUHAN
Saya akan menggunakan pustaka keamanan yang dihormati seperti AppAuth, sehingga Anda tidak perlu membuat kode keamanan sendiri. Perpustakaan membantu kami menghindari potensi kesalahan dan kami mendapatkan fitur keamanan baru secara gratis di masa mendatang.
INTEGRASI APPAUTH
Jika tertarik dengan pendekatan ini, langkah-langkah dan sumber daya saya ini mungkin terbukti berguna:
- Menjalankan Contoh AppAuth
- Kemudian perbarui konfigurasi Anda untuk memastikannya berfungsi dengan Spotify
- Contoh AppAuth Lanjutan mencakup beberapa area yang lebih mendetail untuk mengatasi masalah umum OAuth seluler
KODE
Berikut adalah beberapa kode Swift saya yang mengintegrasikan perpustakaan, dan tidak diperlukan penanganan PKCE tingkat rendah.