Michael Thomas
Michael Thomas

Reputation: 3

.NET Google API access token failing with no refresh token specified

I am trying to set up a class that can wrap around the .NET Google API so that I can use an Access Token that I have previously obtained to access a user's Google Drive. As of right now, I am just trying to get it to work so that I do not require a Refresh Token (more on that in a second). The ultimate goal is for somebody to go through a web page I have set up to authenticate where I obtain both an Access Token and a Refresh Token by directly calling to the Google Rest API (which I store in a database). They can then request to upload/download files onto their Drive on a different page which will first obtain the appropriate information from the database and then use the .NET Google API Library when accessing Drive.

However, when I attempt to access their Drive I get the the following error:

The access token has expired and could not be refreshed. Errors: refresh error, refresh error, refresh error

I know that the Access Token is valid because I obtain it only seconds earlier during my testing. Here is my code for setting up the Drive Service:

  ' NOTE: Code altered for brevity
  Public Sub Initialize(accessToken As String)
        ' Set up the client secret information based on the default constants
        Dim clientSecrets As New ClientSecrets()
        clientSecrets.ClientId = DEFAULT_CLIENT_ID
        clientSecrets.ClientSecret = DEFAULT_CLIENT_SECRET

        ' Set up a token based on the token data we got
        ' NOTE: Is it OK to leave some strings as NULL?
        Dim token As New Responses.TokenResponse()
        token.AccessToken = accessToken
        token.RefreshToken = ""
        token.TokenType = "Bearer"
        token.IssuedUtc = DateTime.Now
        token.ExpiresInSeconds = 3600
        token.Scope = "drive"
        token.IdToken = ""

        ' Set up a flow for the user credential
        Dim init As New GoogleAuthorizationCodeFlow.Initializer()
        init.ClientSecrets = clientSecrets
        init.Scopes = New String() {DriveService.Scope.Drive}
        init.Clock = Google.Apis.Util.SystemClock.Default

        ' Set up everything else and initialize the service
        Dim baseInit As New BaseClientService.Initializer()
        baseInit.HttpClientInitializer = New UserCredential(New GoogleAuthorizationCodeFlow(init), "user", token)
        baseInit.ApplicationName = APP_NAME

        _service = New DriveService(baseInit)
  End Sub

Shortly after that, I then use the following code to request a folder so I can check to see if it exists or not.

  Private Function GetDriveFolder(folderPath As String, ByRef folderIds As String(), Optional createMissingFolders As Boolean = False, Optional parentFolderId As String = "root") As Data.File
    Dim creatingFolderPath As Boolean = False
    Dim currentFolder As Data.File = Nothing
    Dim folderPathSplit As String() = folderPath.Replace("/", "\").Trim("\").Split("\")
    Dim folderIdList As New List(Of String)
    folderIds = {}

    ' Loop through each folder in the path and seek each out until we reach the end
    For x As Integer = 0 To folderPathSplit.Length - 1
        Dim result As FileList = Nothing

        If Not creatingFolderPath Then
            ' Build a list request which we will use to seek out the next folder
            Dim request As FilesResource.ListRequest = _service.Files.List()
            request.Q = "mimeType='application/vnd.google-apps.folder' and name='" & folderPathSplit(x) & "'"
            If currentFolder Is Nothing Then
                request.Q &= " and '" & EscapeDriveValue(parentFolderId) & "' in parents"
            Else
                request.Q &= " and '" & EscapeDriveValue(currentFolder.Id) & "' in parents"
            End If
            request.Spaces = "drive"
            request.Fields = "files(id, name)"

            ' Execute the search, we should only get a single item back
            ' NOTE: Error thrown on this request
            result = request.Execute()
        End If
        ' So on.....

So, I'm just trying to get it to work with only the Access Token for the time being because if it ends up getting refreshed I'll need to know so that I can update my database. However, if I do include the Refresh Token I get the following error:

Error:"unauthorized_client", Description:"Unauthorized", Uri:""

I'm guessing this has something to do with the way I have configured my application through the Dev Console but if I authenticate through the Google API Library by having it launch a browser to get my credentials everything works fine. So, I'm really not sure where to go from here as I haven't found anybody having similar problems and the guides don't cover specifying your own Access Token.

Also, as a quick note this is the URL I am using when having the user authenticate:

String.Format("https://accounts.google.com/o/oauth2/v2/auth?client_id={0}&state={1}&redirect_uri={2}&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&access_type=offline&include_granted_scopes=true&prompt=select_account%20consent&response_type=code", GOOGLEAPI_CLIENTID, validateState, redirectUri)

Thanks for the help!

Upvotes: 0

Views: 1435

Answers (1)

Chris
Chris

Reputation: 1705

If you have an access-token then the simplest way to create a google credential is to use the GoogleCredential.FromAccessToken() method passing in your access token.

This returns you a GoogleCredential instance which you can use to set the HttpClientInitializer property when building the DriveService.

If you then still get an error when accessing the drive service, then it's likely there's something incorrect in how you are asking for the access-token.

Upvotes: 1

Related Questions