Home General
New Blog Posts: Merging Reports - Part 1 and Part 2

Storing OAuth Authentications

edited January 9 in General
We've been putting together OAuth implementations lately and a general question cropped up.

How is RBuilder remembering the authentication? We noticed that sometimes an INI is updated in \USER\AppData\Local\RBuilder. This contains things like an AccessToken, and Expire, etc.

But not all of the time. Under our test applications, the INI gets updated. But under our main application, it does not. Yet even if the INI doesn't get updated, RBuilder is able to remember the last signed in user.

What is the relationship between the INI and the sign in process?

If we wanted to allow the user to force change their signed in user, how can we do that?

Related: If we wanted to switch from using our gmail to 365, how can that be done?

Comments

  • Hi Dusten,

    1. ReportBuilder stores the authentication information in the location defined by the IniStorageSettings. This can be a custom .ini file or the registry and can be accessed from the designer.

    2. The ini stores the AccessToken and RefreshToken (if desired). The AccessToken generally expires one hour from creation so the RefreshToken can be used to obtain another one without the need to re-login.

    3. Currently the only way to force a log-out is to change the OAuth2.AuthStorage property or manually delete the entry from the .ini file.

    4. It is possible to register multiple email plugins at once using the EnableMultiPlugin feature. It is also possible to switch between plugins on the fly if needed. See the following article/examples.

    https://www.digital-metaphors.com/email-multi-service/

    Best Regards,

    Nico Cizik
    Digital Metaphors
    http://www.digital-metaphors.com
  • Another way to log out would be to implement the OnConnectionStart of the email plugin. From here you could clear the TOAuth2Authenticator and a new login will be required.
    Best Regards,

    Nico Cizik
    Digital Metaphors
    http://www.digital-metaphors.com
  • edited January 9
    Thank you Nico.

    Is there a way to support both Indy SMTP and OAuth in the same application?

    It seems that one or the other breaks depending on how the units are included into the application.

    Here's sample code we use to do Indy SMTP:

    var
    lEmail : TPpEmail;
    lIOHandler : TidSSLIOHandlerSocketOpenSSL;
    begin
    TppSMTPPlugin.RegisterClass(TppSMTPIndy);
    TppSMTPPlugIn.UnRegisterClass(TppRESTMailGmail);

    IdLogFile1.Filename := 'C:\Temp\Log.txt';
    IdLogFile1.Active := False;

    ppReport1.EmailSettings.Enabled := True;
    ppReport1.EmailSettings.Clear;
    ppReport1.EmailSettings.HostAddress := 'mail.application.com';
    ppReport1.EmailSettings.UserName := 'ddstwo@application.com';
    ppReport1.EmailSettings.FromAddress := 'ddstwo@application.com';
    ppReport1.EmailSettings.Recipients.Add('noreply@application.com');
    ppReport1.EmailSettings.FromName := 'Dusten';
    ppReport1.EmailSettings.Password := 'test password';
    ppReport1.EmailSettings.Subject := 'Test';

    lEmail := TppEmail(ppReport1.Email);

    lIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
    try
    lIOHandler.Destination := 'mail.gofrontline.com:587';
    lIOHandler.Host := 'mail.gofrontline.com';
    lIOHandler.Port := 587;
    lIOHandler.SSLOptions.SSLVersions := [sslvSSLv3, sslvTLSv1,sslvTLSv1_1, sslvTLSv1_2];

    TppSMTPIndy(lEmail.SMTP).IndySMTP.Intercept := IdLogFile1;
    TppSMTPIndy(lEmail.SMTP).IndySMTP.Port := 587;
    TppSMTPIndy(lEmail.SMTP).IndySMTP.IOHandler := lIOHandler;
    TppSMTPIndy(lEmail.SMTP).IndySMTP.UseTLS := utUseExplicitTLS; //added for KTL
    TppSMTPIndy(lEmail.SMTP).IndySMTP.AuthType := satDefault;
    TppSMTPIndy(lEmail.SMTP).AuthenticateConnection := True;
    TppSMTPIndy(lEmail.SMTP).IndySMTP.UseEhlo := True;

    if Screen.Cursor <> crHourGlass then
    Screen.Cursor := crHourGlass;
    try
    LoadOpenSSLLibrary();
    try
    ppReport1.SendMail;
    finally
    UnLoadOpenSSLLibrary();
    end;
    finally
    Screen.Cursor := crDefault;
    end;
    finally
    lIOHandler.Free;
    end;

    And here's a sample with OAuth:

    TppSMTPPlugin.UnRegisterClass(TppSMTPIndy);
    TppSMTPPlugIn.RegisterClass(TppRESTMailGmail);

    ppReport1.EmailSettings.ConnectionSettings.MailService := 'Gmail';

    ppReport1.EmailSettings.OAuth2.ClientID := 'client ID;
    ppReport1.EmailSettings.OAuth2.ClientSecret := 'secret';
    ppReport1.EmailSettings.Recipients.Add('noreply@gofrontline.com');
    ppReport1.SendMail;

    Depending on how we have the uses clause:

    uses
    ppRESTMailOutlook365,
    ppRESTMailGmail,
    //the rest of the units are to support SMTP
    IdSSLOpenSSL,
    ppSMTPIndy10,
    IdSMTP,
    IdExplicitTLSClientServerBase,
    ppEmail;

    We either get an Access Violation when doing SMTP. The AV happens when we access TppSMTPIndy(lEmail.SMTP).IndySMTP (the IndySMTP member). If we switch the units around we can do Indy but the Oauth send just fails silently. .

    If it helps we are using Delphi 10.4, RBuilder 22.02
  • edited January 9
    Made a little progress on this...but still a bit strange.

    Call TppSMTPPlugin.RegisterClass at the top of each procedure:

    OAuth:
    TppSMTPPlugIn.RegisterClass(TppRESTMailGmail);

    SMTP:
    TppSMTPPlugin.RegisterClass(TppSMTPIndy);

    This allows one to do SMTP first, then OAuth. But once you do OAuth you cannot do SMTP without getting an AV.

    Another issue is you can't do OAuth first. It just dies on the vine.

  • edited January 10
    Hi Dustin,

    1. There is a patch available for RB 22.06 that may solve the "OAuth first" issue you are having. I sent it to you. Registered users with a valid software subscription can contact support@ to receive the patch.

    2. I also sent you an example showing how to switch between plugins in code. Below is a snip from the example for reference. Note that it is not necessary to unregister plugins before registering a new one. It is also not necessary to manually set up Indy for TLS, this is done automatically by setting the UseTLS property to True.
    uses
    ppTypes,
    ppSMTPCustom,
    ppSMTPIndy10,
    ppRESTMailGmail,
    ppRESTMailOutlook365;

    procedure TForm2.Button1Click(Sender: TObject);
    begin
    SetupEmail;
    ppReport1.SendMail;
    end;

    procedure TForm2.SetupEmail;
    begin

    case RadioGroup1.ItemIndex of
    0: SetupIndy;
    1: SetupGmail;
    2: SetupOutlookNet;
    end;

    FCurrentPlugin := TppSMTPPlugin.GetRegisteredClass.MailPluginName;

    ppReport1.EmailSettings.Enabled := True;
    ppReport1.EmailSettings.PreviewInEmailClient := False;

    ppReport1.EmailSettings.Recipients.Clear;
    ppReport1.EmailSettings.Recipients.Add('[Add Recipient]');

    ppReport1.EmailSettings.Subject := 'Test Email - ' + FCurrentPlugin;
    ppReport1.EmailSettings.Body.Text := 'Test Email sent with the ' + FCurrentPlugin + ' plugin.';

    end;

    procedure TForm2.SetupGmail;
    begin
    TppSMTPPlugin.RegisterClass(TppRESTMailGmail);
    ppReport1.EmailSettings.ConnectionSettings.WebMailSetup(ctGmail, '[Client ID]', '[Client Secret]');

    end;

    procedure TForm2.SetupIndy;
    begin
    TppSMTPPlugin.RegisterClass(TppSMTPIndy);

    ppReport1.EmailSettings.ConnectionSettings.UseTLS := True;

    ppReport1.EmailSettings.HostAddress := '[SMTP Server Address]';
    ppReport1.EmailSettings.UserName := '[UserName]';
    ppReport1.EmailSettings.Password := '[Password]';

    end;

    procedure TForm2.SetupOutlookNet;
    begin
    TppSMTPPlugin.RegisterClass(TppRESTMailOutlook365);
    ppReport1.EmailSettings.ConnectionSettings.WebMailSetup(ctOutlookWeb, '[Client ID]', '[Client Secret]');

    end;
    Best Regards,

    Nico Cizik
    Digital Metaphors
    http://www.digital-metaphors.com
Sign In or Register to comment.