Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I'm trying to access my Gmail emails over IMAP using XOAUTH2 in Ruby.

I've successfully generated an access token (and refresh token) by authenticating using OAuth 2.0 with the oauth2 gem. I'm going to use gmail_xoauth to access Gmail over IMAP. So I now need to generate the SASL initial client response, as per the Gmail XOAuth2 docs:

The SASL XOAUTH2 initial client response has the following format:  

    base64("user=" {User} "^Aauth=Bearer " {Access Token} "^A^A")

using the base64 encoding mechanism defined in RFC 4648.
^A represents a Control+A (\001).

I'm not clear how I represent the "Control+A" in my string. Do I simply use ^A?

key = Base64.encode64("user=#{email}^Aauth=Bearer #{access_token_obj.token}^A^A")

This python script uses \1 in place of ^A. I've also tried \001. Whatever I try, when authenticating (in irb) with the result I get:

>> imap = Net::IMAP.new('imap.gmail.com', 993, usessl=true, certs=nil, verify=false)
>> imap.authenticate('XOAUTH2', email, key)
OpenSSL::SSL::SSLError: SSL_write:: bad write retry

That error could be entirely unrelated, but I'm not confident any option I've tried is correct.

share|improve this question
    
That looks entirely like you weren't able to connect to the server. –  Max Jun 5 '13 at 20:05
    
Ah, thanks. Although today I'm instead getting this error: Net::IMAP::NoResponseError: Invalid credentials (Failure). I guess that's progress... –  Phil Gyford Jun 6 '13 at 9:23
add comment

1 Answer 1

up vote 3 down vote accepted

Finally figured it out... I didn't need to do the Base64 encoding step at all!

gmail_xoauth adds the XOAUTH authenticator to Net::IMAP itself. I realised that this only expects the unencoded access_token from Google, rather than the longer Base64-encoded string.

So, if:

email = `[email protected]`
# The result of the OAuth2 dance (as well as a refresh_token):
access_token = 'ya13.AHES6Y3F54_5fAoz_8VuG-7pzQAo3R0_ukt7dhfgRnJh41Q'

then I don't have to Base64 encode anything. I just do:

imap = Net::IMAP.new('imap.gmail.com', 993, usessl=true, certs=nil, verify=false)
imap.authenticate('XOAUTH2', email, access_token)

and I get back:

#<struct Net::IMAP::TaggedResponse tag="RUBY0001", name="OK", data=#<struct Net::IMAP::ResponseText code=nil, text="[email protected] Fred Bloggs authenticated (Success)">, raw_data="RUBY0001 OK [email protected] Fred Bloggs authenticated (Success)\r\n">

(As a bonus, this is a handy Ruby script for getting the access_token from the OAuth dance.)

share|improve this answer
1  
And maybe if I hadn't got distracted by Google's own docs, I would have seen that gmail_xoauth's README describes how to do this. Idiot. –  Phil Gyford Jun 6 '13 at 10:35
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.