diff options
author | Frode Aannevik <frode.aa@gmail.com> | 2019-07-10 21:00:28 +0200 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2019-07-11 19:36:14 -0400 |
commit | b0eaf5191c9bc5b128e347625b7eef998ba63c41 (patch) | |
tree | ca9fe0155e4a01bb84d3aca248b37bf844145f8b /lib | |
parent | 217e85a55d0c1047bef1e2bc41783ccd4629bfc1 (diff) |
Support imaps with oauthbearer authentication (Gmail)
imaps+oauthbearer://user:token@host?token_endpoint=...
- the config Source password is used as access token if
no token_endpoint parameter is set
- the config Source password is used as refresh token if
token_endpoint parameter is set, and used to exchange
with an access token
The implementation has only been tested with Gmail.
source = imaps+oauthbearer://{username}:{refersh_token}@imap.gmail.com:993? \
client_id=XX&\
client_secret=XX&\
token_endpoint=https%3A%2F%2Faccounts.google.com%2Fo%2Foauth2%2Ftoken
client credentials created with
https://console.developers.google.com/apis/credentials
refresh token created with
https://github.com/google/gmail-oauth2-tools/blob/master/python/oauth2.py
rel: https://todo.sr.ht/~sircmpwn/aerc2/42
Diffstat (limited to 'lib')
-rw-r--r-- | lib/oauthbearer.go | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/lib/oauthbearer.go b/lib/oauthbearer.go new file mode 100644 index 0000000..5bcba60 --- /dev/null +++ b/lib/oauthbearer.go @@ -0,0 +1,42 @@ +package lib + +import ( + "context" + "fmt" + "github.com/emersion/go-imap/client" + "github.com/emersion/go-sasl" + "golang.org/x/oauth2" +) + +type OAuthBearer struct { + OAuth2 *oauth2.Config + Enabled bool +} + +func (c *OAuthBearer) exchangeRefreshToken(refreshToken string) (*oauth2.Token, error) { + token := new(oauth2.Token) + token.RefreshToken = refreshToken + token.TokenType = "Bearer" + return c.OAuth2.TokenSource(context.TODO(), token).Token() +} + +func (c *OAuthBearer) Authenticate(username string, password string, client *client.Client) error { + if ok, err := client.SupportAuth(sasl.OAuthBearer); err != nil || !ok { + return fmt.Errorf("OAuthBearer not supported %v", err) + } + + if c.OAuth2.Endpoint.TokenURL != "" { + token, err := c.exchangeRefreshToken(password) + if err != nil { + return err + } + password = token.AccessToken + } + + saslClient := sasl.NewOAuthBearerClient(&sasl.OAuthBearerOptions{ + Username: username, + Token: password, + }) + + return client.Authenticate(saslClient) +} |