Andrew Truckle
Andrew Truckle

Reputation: 19157

Revoke Google Access Token with MFC

I have seen a few questions on this but they are not quite in my scenario. Unless I missed something.

This is how I revoke Google Access:

bool CCalendarSettingsGooglePage::RevokeGoogleAccess()
{
    CInternetSession    iSession;
    CHttpFile           *pWebFile = nullptr;
    CWaitCursor         wait;
    TCHAR               szError[_MAX_PATH];
    DWORD               dwStatusCode;
    CString             strError, strToken, strRevokeURL;

    if (m_strGoogleToken == _T(""))
        return true;

    strRevokeURL.Format(_T("https://accounts.google.com/o/oauth2/revoke?token=%s"), (LPCTSTR)m_strGoogleToken);

    // ask user to go online
    if (InternetGoOnline((LPTSTR)(LPCTSTR)strRevokeURL, GetSafeHwnd(), 0))
    {
        TRY
        {
            // our session should already be open
            // try to open up internet session to my URL
            // AJT v10.4.0 Use flag INTERNET_FLAG_RELOAD
            pWebFile = (CHttpFile*)iSession.OpenURL(strRevokeURL, 1,
            INTERNET_FLAG_TRANSFER_BINARY |
            INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD);

            if (pWebFile != nullptr)
            {
                if (pWebFile->QueryInfoStatusCode(dwStatusCode))
                {
                    if (dwStatusCode == 200) // OK!
                    {
                        return true;
                    }
                    else
                    {
                        // There was a problem!
                        strError.Format(_T("Revoke error: %lu"), dwStatusCode);
                        AfxMessageBox(strError, MB_OK | MB_ICONERROR);
                    }
                }
            }
            else
            {
                AfxMessageBox(_T("Revoke error"), MB_OK | MB_ICONERROR);
            }
        }
            CATCH(CException, e)
        {
            e->GetErrorMessage(szError, _MAX_PATH);
            AfxMessageBox(szError, MB_OK | MB_ICONERROR);
        }
        END_CATCH

        // Tidy up
        if (pWebFile != nullptr)
        {
            pWebFile->Close();
            delete pWebFile;
        }
        iSession.Close();
    }
    return false;
}

My problem is that this approach does not always works. I find that a user has to actually go into their Google Account online, locate their apps, and manually revoke it.

Is there a more robust way to support revoking of an access token?

Upvotes: 2

Views: 253

Answers (1)

Barmak Shemirani
Barmak Shemirani

Reputation: 31619

curl option to revoke token according to Google:

curl -H "Content-type:application/x-www-form-urlencoded" https://accounts.google.com/o/oauth2/revoke?token={token}

So your method should be okay. Maybe the token is already invalid and Google tells you that it doesn't know what to do with the request (the token may have a short life span)

OAuth usually expects "POST" method instead of "GET". You can try the "POST" method instead. In MFC it would be as follows:

DWORD flag = INTERNET_FLAG_SECURE | INTERNET_FLAG_DONT_CACHE |
    INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;

CStringW header;
CStringA query;

{
    CStringW queryW;
    queryW.Format(L"token=%s", token);
    query = CW2A(queryW, CP_UTF8);
}

header.Format(L"\
Content-Type: application/x-www-form-urlencoded\r\n\
Content-length: %d\r\n\
Connection: Close\r\n\
\r\n", query.GetLength());

CInternetSession session;
CHttpConnection *connection = session.GetHttpConnection(L"accounts.google.com", 
    (INTERNET_PORT)INTERNET_DEFAULT_HTTPS_PORT);
if(connection)
{
    CHttpFile *file = connection->OpenRequest(L"POST", 
        L"o/oauth2/revoke", L"http://localhost", 1, NULL, NULL, flag);
    if(file)
    {
        if(file->SendRequest(header, 
            query.GetBuffer(), query.GetLength()))
        {
            DWORD dwRet;
            if (file->QueryInfoStatusCode(dwRet))
            {
                if (dwRet == 200 || dwRet == 400)
                {
                    //success!
                }
            }
        }
        delete file;
    }
    delete connection;
}

Above code uses Unicode version, it has to convert UTF-16 query to UTF-8...

Upvotes: 2

Related Questions