Storing OAuth Authentications
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?
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
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/
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
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
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.
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.
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com