使用Alamofire 4和OAuth2在Swift中发起POST请求时遇401错误
先给你捋清楚两个问题的优先级:你看到的CredStore - performQuery - Error copying matching creds. Error=-25300其实是系统钥匙串的一个警告,和你的授权失败没有直接关系——很多开发者用Alamofire请求HTTPS接口时都会碰到它,不用太在意,咱们重点解决导致401的核心问题。
你的代码里有几个关键错误,我帮你逐个拆解修正:
1. Grant Type 匹配错误
你采用的是Application Only OAuth模式,对应的grant_type必须是client_credentials,但你代码里用的https://oauth.reddit.com/grants/installed_client是Installed App类型的授权参数,完全不匹配当前模式。
2. Basic认证字符串格式错误
Basic认证的规则是把客户端ID:密码(注意中间的冒号分隔符)转成Base64编码,你代码里写的String(format: "%@%@", username, password)少了关键的冒号,导致认证信息完全无效,这是401的核心原因之一。
3. 请求编码方式错误
Reddit的access_token接口要求用表单格式(application/x-www-form-urlencoded)提交参数,但你用了JSONEncoding.default,这会让服务端无法正确解析你的请求参数。
4. 多余参数干扰
Application Only OAuth不需要device_id参数,这个参数是给Installed App授权模式用的,直接删掉即可。
修正后的完整请求代码
把你AppDelegate里的请求部分替换成下面这段:
guard let url = URL(string: "https://www.reddit.com/api/v1/access_token") else { return false } // Application Only OAuth仅需指定grant_type参数 let params: Parameters = [ "grant_type": "client_credentials" ] let username = "MY_CLIENT_ID" let password = "" // 注意添加客户端ID和密码之间的冒号 let loginString = String(format: "%@:%@", username, password) guard let loginData = loginString.data(using: .utf8) else { return false } let base64EncodedString = loginData.base64EncodedString() let headers = ["Authorization": "Basic \(base64EncodedString)"] // 使用URLEncoding.default适配表单提交要求 Alamofire.request(url, method: .post, parameters: params, encoding: URLEncoding.default, headers: headers).responseJSON { response in print(response) }
最后再确认两个配置细节:
- 你的Reddit开发者后台里,应用类型是不是设置成了Script?Application Only OAuth仅支持Script或Web App类型的应用;
- 重定向URI是不是和你
Info.plist里配置的APP_SCHEME完全一致?比如your-app-scheme://callback,确保授权后能正确跳转回应用。
这样修改后就能正常获取到access token了。
内容的提问来源于stack exchange,提问作者Garret Koontz




