I'm trying to connect from Swift app I built to Google's Reply to Reviews
API which is part of https://www.googleapis.com/auth/androidpublisher
scope, in order to get a list of a specific app reviews. I created a Service Account and with that I managed to created a JWT token, then tried to make a GET request to the API, but i'm getting an error:
{
"error": {
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "CREDENTIALS_MISSING",
"domain": "googleapis.com",
"metadata": {
"service": "androidpublisher.googleapis.com",
"method": "google.play.publishingapi.v3.ReviewsService.List"
}
}
]
}
}
This is the request url:
https://www.googleapis.com/androidpublisher/v3/applications/<APP_PACKAGE>/reviews?access_token=<JWT-TOKEN>
This is my request code:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let auth = Authentication()
let jwt = auth.generateJWT()
self.retriveReviews(packageIdentifier: "<APP_PACKAGE>", auth: jwt!)
}
func retriveReviews(packageIdentifier: String, auth: String) {
let url = URL(string: "https://www.googleapis.com/androidpublisher/v3/applications/\(packageIdentifier)/reviews?access_token=\(auth)")
print("Request URL: \(url)")
var request = URLRequest(url: url!)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else { return }
print(String(data: data, encoding: .utf8)!)
}
task.resume()
}
JWT Token:
import JWTKit
import UIKit
class Authentication: NSObject {
func generateJWT() -> String? {
struct Header: JWTPayload {
enum CodingKeys: String, CodingKey {
case alg = "alg"
case type = "typ"
}
var alg = "RS256"
var type: String = "JWT"
func verify(using signer: JWTSigner) throws {
// print(self.expireTime > Date().timeIntervalSince1970)
fatalError()
}
}
struct Payload: JWTPayload {
enum CodingKeys: String, CodingKey {
case email = "iss"
case scope = "scope"
case aud = "aud"
case createdAt = "iat"
case expireTime = "exp"
}
var email: String = "XXXXX@XXXXXX.iam.gserviceaccount.com"
var scope: String = "https://www.googleapis.com/auth/androidpublisher"
var aud: String = "https://oauth2.googleapis.com/token"
var createdAt: Double = Date().timeIntervalSince1970
var expireTime: Double = Date().advanced(by: 1000).timeIntervalSince1970
func verify(using signer: JWTSigner) throws {
print(self.expireTime > Date().timeIntervalSince1970)
fatalError()
}
}
do {
if let certificatePath = Bundle.main.path(forResource: "k_created", ofType: "pem") {
let certificateUrl = URL(fileURLWithPath: certificatePath)
let certififcateData = try Data(contentsOf: certificateUrl)
let signers = JWTSigners()
let key = try RSAKey.private(pem: certififcateData)
signers.use(.rs256(key: key))
// MARK: HEADER NOT USED
let header = Header()
let payload = Payload()
let jwt = try signers.sign(payload)
// let jwt = try signers.sign(payload)
print("JWT: \(jwt)")
return jwt
} else {
return nil
}
} catch {
print(error)
return nil
}
}
}
What am I doing wrong? or maybe there is a step I am missing?