Introduction​

Email providers such as Google GMail allow authentication of the Smtp and Pop3 client via the OAuth2 security protocol. Furthermore, it is foreseeable that sooner or later other authentications will no longer be allowed. Google has already announced this step.

The OAuth2 security protocol can be implemented from Xbase++ with the OAuth2 asset, which can be added to an application via the Asset Manager of the Xbase++ Workbench. For this purpose, the code grant example included with the asset, and for which an example target can be added to the project, only needs to be marginally modified.

The Xbase++ The Xbase++ Workbench Asset Management and the OAuth2 asset are explained in different Articles.

The main focus of this article is on the GMail specific settings that have to be communicated to the GMail peer with the Authorization Request, the Token Request and the Refresh Request.

Preparation​

For sending and receiving emails via the Smtp and Pop3 protocol, the GMail account must be prepared. This is not the subject of this article. You can find a description of this in Google's documentation: Setting up OAuth 2.0. As a result, you will get a client Id and a secret that you need for OAuth2 authorization.

OAuth2 configuration​

The configuration for OAuth2 is done in 4 methods of a class derived from OAuth2CodeGrant. These methods are :configureAuthorizationRequest(), :configureRequestCommon(), :configureTokenRequest() and :configureRefreshRequest().

:configureRequestCommon()​

Xbase++:
METHOD GMailCodeGrant:configureRequestCommon( oRequest )
   // Todo: Assign your Client Id here
   oRequest:client_id      := ""
   oRequest:redirect_uri   := "http://localhost:"+Var2Char(::getRedirectPort())+"/RedirectionSink/redirected"
RETURN SELF

Here the configuration is performed, which is valid for the authorization request, the token request as well as the refresh request. In particular, the :client_id must be specified, which you received when setting up your GMail account for OAuth2. The value for :redirect_uri specifies the OAuth2 asset endpoint that will be called during authorization and that must be identical for a token request.

:configureAuthorizationRequest()​

Xbase++:
METHOD GMailCodeGrant:configureAuthorizationRequest( oAuthorizationRequest )
   oAuthorizationRequest:ServerUrl     := "https://accounts.google.com/o/oauth2/auth"
   oAuthorizationRequest:response_type := "code"
   oAuthorizationRequest:state         := UUIDToChar( UUIDCreate() )
   oAuthorizationRequest:scope          := "https://mail.google.com/"
RETURN SELF

The values that will be sent to the Google Authorization Server are entered here. During the authorization it is necessary that a user enters his password and authorizes the application for the email exchange. Compared to the oridinary code grant example source code, the values for :ServerUrl and :scope have to be adjusted here.

:configureTokenRequest()​

Xbase++:
METHOD GMailCodeGrant:configureTokenRequest( oTokenRequest, oAuthorizationResult )
   oTokenRequest:ServerUrl       := "https://oauth2.googleapis.com/token"
   // Todo: Assign your Client Secret here
   oTokenRequest:client_secret   := ""
   oTokenRequest:grant_type      := "authorization_code"
   oTokenRequest:code            := oAuthorizationResult:Code
RETURN .T.

Again, the GMail specific endpoint must be specified in :ServerUrl. You must also specify the client secret that you received when setting up the GMail account for OAuth2.

:configureRefreshRequest()​

Xbase++:
METHOD GMailCodeGrant:configureRefreshRequest( oRefreshRequest, cRefreshToken )
   oRefreshRequest:ServerUrl     := "https://oauth2.googleapis.com/token"
   oRefreshRequest:grant_type    := "refresh_token"
   oRefreshRequest:refresh_token := cRefreshToken
   // Todo: Assign your Client Secret here
   oRefreshRequest:client_secret := ""
RETURN self

The refresh request must be handled in the same way as the token request. The value for :ServerUrl must be adjusted and the value for the client secret must be entered.

The wallet​

The OAuth2 asset supports a wallet. This is a class that must be derived from TokenWallet and must implement the :readToken() and :writeToken() methods. Through the wallet, the OAuth2 asset handles the persistence of the token and the refresh token. A reference implementation is shown in the header of the CodeGrant example source code.

LoginForm​

For authorization by the user, a user interface must be implemented for the OAuth2 asset. To do this, derive from the LoginFormAdapter class and implement the :eek:pen() and :close() methods. In the code grant example, the LoginForm opens a WebBrowser instance. The implementation can remain as it is.

Setup​

To perform the authorization and the requests of the token and refresh token, the code grant flow, the LoginForm and the wallet must be connected. An instance of the OAuth2Client class must also be instantiated and passed the to flow:

Xbase++:
   // Instantiate the grant and connect the adapter which
   // displays the login form.
   oCodeGrant := GMailCodeGrant():new()
   oCodeGrant:setLoginFormAdapter( LoginForm():new() )

   // Create the wallet and pass it to the Code Grant Flow
   oWallet := MyWallet():new()
   oCodeGrant:setWallet( oWallet )


   // Instantiate the OAuth2Client and connect the grant flow.
   oOAuth2Client := OAuth2Client():new()
   oOAuth2Client:setOAuth2Grant( oCodeGrant )

Sending and receiving e-mail​

The actual task of sending and receiving e-mails is very simple. The access token is retrieved via the instance of the OAuth2Client class. If no Access Token is available or if it is expired, a new Access Token is determined via the Refresh Token. If the refresh token is also not valid, the user's consent is obtained via the user interface and then an access token with a new refresh token is obtained from the GMail remote station:

Xbase++:
   cAccessToken := oOAuth2Client:getAccessToken()

This access token can now be used just like a password to allow the Smtp and Pop3 client to connect against the GMail remote site. The only thing left to do is to set the "xoauth2" authentication protocol for the connection:

Xbase++:
   oSmtpClient:setAuthentication( "xoauth2" )
   oSmtpClient:connect( cEmailAddress, cAccessToken )

Xbase++:
   oPop3Client:setAuthentication( "xoauth2" )
   oPop3Client:connect()

Summary​

The Xbase++ OAuth2 asset is suitable to get an access token to connect instances of the classes SmtpClient and Pop3Client to the GMail Smtp and Pop3 servers.

For this only marginal modifications of the code grant example are necessary.

References​