[The problem is solved, I actually just can't select my answer as the solution yet.]
I'm working on a video upload feature for a mobile app, with YouTube Data API; but I keep having a 401 error at the query's execution.
I'm using Firebase to provide me OAuth & API keys from Google Developer.
I tried to see if the PLIST file furnished by Firebase suffered any change, and even with an other.
I tried to reset the iOS Simulator, to uninstall the app and to terminate the permissions from my account for the app through GIDSignIn.sharedInstance().disconnect()
.
I tried to see with other StackOverFlow questions, but they all are about other languages, or even "raw" HTTP requests.
In my AppDelegate file, I have those lines for the connection with Firebase and Google:
FirebaseApp.configure()
GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
and this method (and a very similar one that I won't show here):
func application( _ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any ) -> Bool {
return GIDSignIn.sharedInstance().handle( url,
sourceApplication: sourceApplication,
annotation: annotation )
}
In my controller associated class, I have those methods to create the query:
private func uploadVideo( withVideoObject video: GTLRYouTube_Video, resumeUploadLocationURL locationURL: URL? ) throws {
let query = try uploadQuery( _video: video, resumeUploadLocationURL: locationURL )!
// [ progress related feedback ]
YouTubeUploadController.uploadFileTicket = self.service.executeQuery( query,
delegate: self.controller!,
didFinish: #selector( self.controller!.displayResultWithTicket(ticket:finishedWithObject:error:) ) )
}
private func uploadQuery( _video: GTLRYouTube_Video, resumeUploadLocationURL locationURL: URL? ) throws -> GTLRYouTubeQuery_VideosInsert? {
let fileToUploadURL = URL( fileURLWithPath: "\(self.controller!.uploadPathField)" )
if !( try! fileToUploadURL.checkPromisedItemIsReachable() ) {
throw YouTubeCustomError.init( _kind: .fileNotFound )
}
// Get a file handle for the upload data.
let uploadParameters = prepareUploadParameters( fileToUploadURL: fileToUploadURL, locationURL: locationURL )
return GTLRYouTubeQuery_VideosInsert.query( withObject: _video, part: "snippet,status", uploadParameters: uploadParameters )
}
It sends an error through displayResultWithTicket(ticket:finishedWithObject:error:)
:
"This operation couldn't be completed. (com.google.HTTPStatus error 401.)"
No given failureReason, nor recoverySuggestion.
Thanks in advance.
Response body:
Here's the GTMSessionFetcher's HTTP answer logs for an upload attempt:
Response body: (178 bytes)
{
"error" : {
"message" : "Login Required",
"errors" : [
{
"message" : "Login Required",
"locationType" : "header",
"reason" : "required",
"domain" : "global",
"location" : "Authorization"
}
],
"code" : 401
}
}
Request Headers
Request: POST https://www.googleapis.com/resumable/upload/youtube/v3/videos?part=snippet%2Cstatus&prettyPrint=false
Request headers:
Accept: application/json
Cache-Control: no-cache
Content-Type: application/json; charset=utf-8
User-Agent: org.cocoapods.GoogleAPIClientForREST/1.3.8 google-api-objc-client/3.0 iPhone/12.2 hw/sim (gzip) (GTMSUF/1)
X-Goog-Upload-Command: start
X-Goog-Upload-Content-Length: 2614231
X-Goog-Upload-Content-Type: video/mp4
X-Goog-Upload-Protocol: resumable
So in my case, I was lacking the GTRLService authorizer affectation in my GIDSignInDelegate signIn method:
service.authorizer = user.authentication.fetcherAuthorizer()
I assume it can be also done in other methods, but it is the core point in which it is initialized.
I did it through an ObjC write accessor, because I didn't find a way to create/obtain a GTRLService instance in Swift and I used a ObjC singleton class to obtain it, and I was unsure if we could access the GTRLService instance methods in Swift if it was initialized in ObjC.
+ (void)setSharedInstanceAuthorizer:(id <GTMFetcherAuthorizationProtocol>)_authorizer {
if (sharedInstance == nil) {
sharedInstance = [GTLRYouTubeService new];
}
sharedInstance.authorizer = _authorizer;
};
If that doesn't solve the problem, then @stvar's answers in the comments of the question might actually do.