SpotifyPKCE認証フローが「code_verifierが正しくありませんでした」を返します
Spotify APIの認証ガイドに従って、PKCEを使用してアプリを認証しています。
現在のところ、デバッグ用に事前に計算されたチャレンジを備えたダミーコードベリファイアを使用しています。これらの値は、複数のオンラインツール(SHA256、SHA256、base64url、base64url)を使用して計算され、Swiftで記述したハッシュ/エンコード関数から返された値と一致します。上記のリンクを使用して、これらを確認してください。
let verifier = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
let challenge = "66d34fba71f8f450f7e45598853e53bfc23bbd129027cbb131a2f4ffd7878cd0"
let challengeBase64URL = "NjZkMzRmYmE3MWY4ZjQ1MGY3ZTQ1NTk4ODUzZTUzYmZjMjNiYmQxMjkwMjdjYmIxMzFhMmY0ZmZkNzg3OGNkMA"
ASWebAuthenticationSessionを使用して、次のように手順2で最初のリクエストを行います。
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()
ではhandleLoginResponse
、ステップ3の応答を解析し、Alamofireを使用してステップ4のネットワーク要求を行います。
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は、Swift内からcURLリクエストを行うためのインターフェースを作成します。呼び出すcURLDescription()
ことで、実際のcURLコマンドが最終的にどのようになるかを正確に確認できます。
$ 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"
読むのは少し難しいですが、リクエストは正しく行われていると確信しています。
ただし、手順4では、サーバーから常に次のエラーメッセージが表示されます。
error = "invalid_grant";
"error_description" = "code_verifier was incorrect";
私は数時間の間に多くのことを試しましたが、それでも理解できません。どんなポインタでも大歓迎です。ありがとう!
回答
あなたの問題は、SHAハッシュの生のバイトがbase64edである必要があるものであるということです。AlamofireとSpotifyPKCEを使用するアプリにも取り組んでおり、コードのチャレンジで問題が発生しました。私がしたことは、Swift 3用に作成されたAuth0ドキュメントのコードを使用し、Swift5で動作するように変更したことです。
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"))
これがお役に立てば幸いです。
このオンラインPKCEベリファイアを使用したとき、ベリファイアに対して別のチャレンジが発生したため、ツールが提供する値で再試行する可能性があります。
全体的なセキュリティ
AppAuthなどの尊敬されているセキュリティライブラリを使用するので、セキュリティを自分でコーディングする必要はありません。ライブラリは、潜在的なミスを回避するのに役立ち、将来的には新しいセキュリティ機能を無料で入手できます。
APPAUTHの統合
このアプローチに興味がある場合は、これらの手順と私のリソースが役立つ可能性があります。
- AppAuthサンプルの実行
- 次に、設定を更新して、Spotifyで機能することを確認します
- 高度なAppAuthサンプルは、一般的なモバイルOAuthの問題を回避するためのより詳細な領域をカバーしています
コード
ここではいくつかある鉱山のスウィフトコードライブラリを統合し、必要な取り扱いなし低レベルPKCEはありません。