Error 403 and other troubles on Youtube Video Upload IOS

78 views
Skip to first unread message

Michela Corazza

unread,
Aug 3, 2017, 10:54:22 AM8/3/17
to Google APIs Client Library for Objective-C

In my project wanna have a flow like this:


Users record short videos -> they upload the videos on my channel -> end


- (void)doAuthWithoutCodeExchange:(OIDServiceConfiguration *)configuration
                         clientID:(NSString *)clientID
                     clientSecret:(NSString *)clientSecret {
    NSURL *redirectURI = [NSURL URLWithString:kRedirectURI];

    // builds authentication request
    OIDAuthorizationRequest *request =
    [[OIDAuthorizationRequest alloc] initWithConfiguration:configuration
                                                  clientId:clientID
                                              clientSecret:clientSecret
                                                    scopes:@[ OIDScopeOpenID, OIDScopeProfile ]
                                               redirectURL:redirectURI
                                              responseType:OIDResponseTypeCode
                                      additionalParameters:nil];
    // performs authentication request
    AppDelegate *appDelegate = (AppDelegate *) [UIApplication sharedApplication].delegate;
    [self logMessage:@"Initiating authorization request %@", request];
    appDelegate.currentAuthorizationFlow =
    [OIDAuthorizationService presentAuthorizationRequest:request
                                presentingViewController:self
                                                callback:^(OIDAuthorizationResponse *_Nullable authorizationResponse,
                                                           NSError *_Nullable error) {
                                                    if (authorizationResponse) {
                                                        OIDAuthState *authState =
                                                        [[OIDAuthState alloc] initWithAuthorizationResponse:authorizationResponse];
                                                        [self setAuthState:authState];

                                                        [self logMessage:@"Authorization response with code: %@",
                                                         authorizationResponse.authorizationCode];
                                                        // could just call [self tokenExchange:nil] directly, but will let the user initiate it.

                                                        OIDTokenRequest *tokenExchangeRequest =
                                                        [_authState.lastAuthorizationResponse tokenExchangeRequest];

                                                        [self logMessage:@"Performing authorization code exchange with request [%@]",
                                                         tokenExchangeRequest];

                                                        [OIDAuthorizationService performTokenRequest:tokenExchangeRequest
                                                                                            callback:^(OIDTokenResponse *_Nullable tokenResponse,
                                                                                                       NSError *_Nullable error) {

                                                                                                if (!tokenResponse) {
                                                                                                    [self logMessage:@"Token exchange error: %@", [error localizedDescription]];
                                                                                                } else {
                                                                                                    [self logMessage:@"Received token response with accessToken: %@", tokenResponse.accessToken];
                                                                                                }

                                                                                                [_authState updateWithTokenResponse:tokenResponse error:error];

                                                                                                GTMAppAuthFetcherAuthorization *gtmAuthorization =
                                                                                                [[GTMAppAuthFetcherAuthorization alloc] initWithAuthState:authState];

                                                                                                // Sets the authorizer on the GTLRYouTubeService object so API calls will be authenticated.
                                                                                                self.youTubeService.authorizer = gtmAuthorization;

                                                                                                // Serializes authorization to keychain in GTMAppAuth format.
                                                                                                [GTMAppAuthFetcherAuthorization saveAuthorization:gtmAuthorization
                                                                                                                                toKeychainForName:kGTMAppAuthKeychainItemName];

                                                                                                [self uploadVideoFile];

                                                                                            }];







                                                    } else {
                                                        [self logMessage:@"Authorization error: %@", [error localizedDescription]];
                                                    }
                                                }];
}



This method cause this flow:

app send user to google login page in safari -> user log with his credentials -> after login, user is redirect back to my app -> the block success call the method UploadVideo.

This part of the flow seems to work correctly, i obtain a valid token as the log says. The second part is the video upload that consist in two main methods:


- (void)uploadVideoFile {
    // Collect the metadata for the upload from the user interface.
    // Status.
    GTLRYouTube_VideoStatus *status = [GTLRYouTube_VideoStatus object];
    status.privacyStatus = @"public";

    // Snippet.
    GTLRYouTube_VideoSnippet *snippet = [GTLRYouTube_VideoSnippet object];
    snippet.title = @"title";
    NSString *desc = @"description";
    if (desc.length > 0) {
        snippet.descriptionProperty = desc;
    }
    NSString *tagsStr = @"tags";
    if (tagsStr.length > 0) {
        snippet.tags = [tagsStr componentsSeparatedByString:@","];
    }

    GTLRYouTube_Video *video = [GTLRYouTube_Video object];
    video.status = status;
    video.snippet = snippet;

    [self uploadVideoWithVideoObject:video
             resumeUploadLocationURL:nil];
}


- (void)uploadVideoWithVideoObject:(GTLRYouTube_Video *)video
           resumeUploadLocationURL:(NSURL *)locationURL {
    NSURL *fileToUploadURL = [NSURL fileURLWithPath:self.VideoUrlCri.path];
    NSError *fileError;
    NSLog(@"step");
    if (![fileToUploadURL checkPromisedItemIsReachableAndReturnError:&fileError]) {

        NSLog(@"exit");

        return;
    }

    // Get a file handle for the upload data.
    NSString *filename = [fileToUploadURL lastPathComponent];
    NSString *mimeType = [self MIMETypeForFilename:filename
                                   defaultMIMEType:@"video/mp4"];
    GTLRUploadParameters *uploadParameters =
    [GTLRUploadParameters uploadParametersWithFileURL:fileToUploadURL
                                             MIMEType:mimeType];
    uploadParameters.uploadLocationURL = locationURL;

    GTLRYouTubeQuery_VideosInsert *query =
    [GTLRYouTubeQuery_VideosInsert queryWithObject:video
                                              part:@"snippet,status"
                                  uploadParameters:uploadParameters];


    query.executionParameters.uploadProgressBlock = ^(GTLRServiceTicket *ticket,
                                                      unsigned long long numberOfBytesRead,
                                                      unsigned long long dataLength) {
        NSLog(@"upload progress");

    };

    GTLRYouTubeService *service = self.youTubeService;
    _uploadFileTicket = [service executeQuery:query
                            completionHandler:^(GTLRServiceTicket *callbackTicket,
                                                GTLRYouTube_Video *uploadedVideo,
                                                NSError *callbackError) {

                                if (callbackError == nil) {
                                    NSLog(@"uploaded");


                                } else {

                                     NSLog(@"error %@",callbackError);
                                }


                            }];

}

- (NSString *)MIMETypeForFilename:(NSString *)filename
                  defaultMIMEType:(NSString *)defaultType {
    NSString *result = defaultType;
    NSString *extension = [filename pathExtension];
    CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
                                                            (__bridge CFStringRef)extension, NULL);
    if (uti) {
        CFStringRef cfMIMEType = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType);
        if (cfMIMEType) {
            result = CFBridgingRelease(cfMIMEType);
        }
        CFRelease(uti);
    }
    return result;
}



I obtain a 403 error in NSLog(@"error %@",callbackError); and i can't see error details because the are something like :


data=<7b226572 726f7222 3a7b2265 72726f72 73223a5b 7b22646f 6d61696e 223a2267 6c6f6261 6c222c22 72656173 6f6e223a 22696e73 75666669 ... 61676522 3a22496e 73756666 69636965 6e742050 65726d69 7373696f 6e227d7d>}

In google api console i have created a Client Oauth for my application bundle and an API key, i use those values for my connection, it seems they works correctly because i obtain a valid token. Anyway, there someone who can help me or point me in the right direction about this error? Or there someone who knows a working example about a video upload for IOS and not for MAC ? There something weird in my code?

Thomas Van Lenten

unread,
Aug 3, 2017, 12:00:44 PM8/3/17
to Google APIs Client Library for Objective-C
From a quick look, you seem to only be requesting the scopes around openid, and not actually adding in the scopes needed for permission to upload a video, you probably want to include kGTLRAuthScopeYouTube in your list of scopes.

YouTube errors seem like they might have recently changed to encode the json within the error instead of inlining it; this came up in https://github.com/google/google-api-objectivec-client-for-rest/issues/143 also.  If you can get an http log (link in the issue for how to get one), we can follow up with internally.

TVL
Reply all
Reply to author
Forward
0 new messages