Jump to content
Clément

Windows Service, gmail, and OAuth2 blues

Recommended Posts

Hi,

I'm using D11.2 and ICS 8.71

 

I'm working on a two-part project. Desktop application + Windows Service.
All UI part is done in the Desktop Application. For example: I can set smtp server parameters within the Desktop application.
The Service will get the smtp parameters and effectively send the email. The email can be sent by several triggers.
For example: running low on disk space, a specific folder is larger than specified, etc..
For normal smtp accounts everything works smoothly!
 

Here enters the OAuth2.
If I understood correctly, OAuth2 requires a user intervention during the sending process, which in my case will happen in the service -> no UI -> no Browser!
I was wondering if it's possible to "send the required data" from the Service, so the desktop could display the Browser and allow the user to interact, get the required information, and send it back to the service. Hopefully, this authentication will happen once or twice.

Since it's possible for an external browser (different process than the application which send the mail ) to collect the data, and validate the application, I was wondering if it's possible to take things one step further, and send the data to the service.
(I would not like to send an email from the Desktop Application, if it comes to that, I prefer having a separate application which would handle the authentication).

 

In order to communicate properly, would it be possible to have IcsRestEmail in my Desktop Application, collect the data and get back to the service?
 

procedure TSslSmtpTestForm.SslSmtpClientGetNewToken(Sender: TObject);           { V8.65 }
begin
    if NOT IcsRestEmail1.GetNewToken(True, Self) then   // allow interaction, waits for broweser window to be completed, V8.71 added self
        Display('Failed to get OAuth2 Bearer Token')
    else begin
        if (Pos (IcsRestEmail1.NewAccEmail, SslSmtpClient.UserName) = 0) and
                                              (IcsRestEmail1.NewAccEmail <> '') then
            Display('OAuth2 Token for Wrong Account, Expected: ' +
                 SslSmtpClient.Username + ', Got: ' + IcsRestEmail1.NewAccEmail)
        else  begin
            SslSmtpClient.OAuthToken := IcsRestEmail1.AccToken;
            SslSmtpClient.TokenExpireDT := IcsRestEmail1.AccExpireDT;
            Display('Got New OAuth2 Bearer Token OK');
        end;
    end;
end;

I should send a blocking IPC request from this event, wait until the user interacted, and return with OAuthToken and TokenExpireDT.
How often would AccToken require renewing? It's seems a lot of work and the user might end up having email issues when the token expiration hits (probably on a Sunday)

 

On the other hand, I use Thunderbird to send emails from my gmail account. And I did only once the validation process. Since my application is not Thunderbird, it might differ.

Hopefully, it's possible to have some nice code written to solve this.

 

Have you done such a thing? Is it even possible?

 

Clément

 

 

Edited by Clément

Share this post


Link to post

Technically, you can use the event you posted to get a new token from the desktop through interaction, ICS V8.71 now uses an internal browser window that makes it seamless. 

 

But it's not really necessary, using the same secrets in service and desktop applications, get a refresh token using the desktop and manually paste that to the configuration file for the service, use the IcsLoadRestEmailFromIni function to load it from an INI file per the ICS server samples.  The refresh token rarely expires so only needs to be updated if you change the secrets or deliberately invalidate it online. 

 

I've been doing this with the IcsMailQueue in my web, rest and FTP servers on all my different servers, all with the same refresh token, for two or three years.

 

Angus

 

  • Like 1

Share this post


Link to post

Should clarify my last message about the long lived refresh token, this is for a specific admin email account used by the server to call for help when it's unhappy. 

 

If the service application needs to send from multiple email accounts, you'll need to be more creative. 

 

Angus

 

  • Like 1

Share this post


Link to post

Just for clarification,

 

I can use only IcsRestEmail in my desktop application. The user will enter it's account setting, and I will call "GetNewToken". If everthing works fine, I'll endup with AccToken and AccExpireDT assigned, and in my case I will store them in my database.
Later, the service will read those parameter and send the mail ... this is great!

 

Thanks!

Share this post


Link to post

The OAuth2 Access Token has a short life, for Google it is usually one hour, little point in saving it in a database, unless you are using that to share information between applications.  That is why you instead store the Refresh Token and use OAuth2 without interaction to get a new Access Token each time you send an email.

 

Angus

 

  • Like 1

Share this post


Link to post

I will protect both ClientID and ClientKey in my desktop application. They will only get unprotected to assign the corresponding properties in IcsRestEmail.
How is this call done? Are they transmitted to google protected?

Share this post


Link to post
9 minutes ago, Angus Robertson said:

The OAuth2 Access Token has a short life, for Google it is usually one hour, little point in saving it in a database, unless you are using that to share information between applications.  That is why you instead store the Refresh Token and use OAuth2 without interaction to get a new Access Token each time you send an email.

 

Angus

 

I see. I can use the refresh token even if "some days" has passed? For example, some tasks might run over a weekend. I will use the refresh token on Sunday to send the last email, and only refresh it again next saturday before sending the first email.

Edited by Clément

Share this post


Link to post

Yes, as I said yesterday the Refresh Token will often stay valid for months or even years and can be treated like a password and kept securely, but unlike a password it can be revoked at any time if compromised forcing a new interactive login to get a new Refresh Token.  Note you have no idea about the life of the Refresh Token, so you must allow for it to be rejected.

 

Angus

 

 

 

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×