diff --git a/demo/tutorial12/AuthFilter.pas b/demo/tutorial12/AuthFilter.pas
new file mode 100644
index 00000000..8804dae8
--- /dev/null
+++ b/demo/tutorial12/AuthFilter.pas
@@ -0,0 +1,102 @@
+(*
+
+ Daraja HTTP Framework
+ Copyright (C) Michael Justin
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+
+ You can be released from the requirements of the license by purchasing
+ a commercial license. Buying such a license is mandatory as soon as you
+ develop commercial activities involving the Daraja framework without
+ disclosing the source code of your own applications. These activities
+ include: offering paid services to customers as an ASP, shipping Daraja
+ with a closed source product.
+
+*)
+
+unit AuthFilter;
+
+// note: this is unsupported example code
+
+interface
+
+uses
+ djWebFilter,
+ djServerContext,
+ djTypes,
+ djInterfaces,
+ Classes, SysUtils;
+
+type
+
+ { TAuthFilter }
+
+ TAuthFilter = class(TdjWebFilter)
+ private
+ AuthorizeEndpoint: string;
+ ClientID: string;
+ RedirectURI: string;
+ public
+ procedure Init(const Config: IWebFilterConfig); override;
+ procedure DoFilter(Context: TdjServerContext; Request: TdjRequest;
+ Response: TdjResponse; const Chain: IWebFilterChain); override;
+ end;
+
+implementation
+
+function CreateGUIDString: string;
+var
+ Guid: TGUID;
+begin
+ CreateGUID(Guid);
+ Result := GUIDToString(Guid);
+end;
+
+{ TAuthFilter }
+
+procedure TAuthFilter.Init(const Config: IWebFilterConfig);
+begin
+ AuthorizeEndpoint := Config.GetInitParameter('AuthorizeEndpoint');
+ ClientID := Config.GetInitParameter('ClientID');
+ RedirectURI := Config.GetInitParameter('RedirectURI');
+end;
+
+procedure TAuthFilter.DoFilter(Context: TdjServerContext; Request: TdjRequest;
+ Response: TdjResponse; const Chain: IWebFilterChain);
+var
+ AccessToken: string;
+ State: string;
+begin
+ AccessToken := Request.Session.Content.Values['access_token'];
+ if AccessToken = '' then
+ begin
+ State := CreateGUIDString;
+ Response.Session.Content.Values['state'] := State;
+ Response.Redirect(AuthorizeEndpoint
+ + '?client_id=' + ClientID // Your app registration's Application (client) ID
+ + '&response_type=token' // Requests an access token
+ + '&redirect_uri=' + RedirectURI
+ + '&scope=User.Read Mail.Send' // Request read profile and send mail permission
+ + '&response_mode=form_post'
+ + '&state=' + State
+ );
+ end
+ else
+ begin
+ Chain.DoFilter(Context, Request, Response); // pass
+ end;
+end;
+
+end.
diff --git a/demo/tutorial12/AuthResponseResource.pas b/demo/tutorial12/AuthResponseResource.pas
new file mode 100644
index 00000000..97760fb6
--- /dev/null
+++ b/demo/tutorial12/AuthResponseResource.pas
@@ -0,0 +1,79 @@
+(*
+
+ Daraja HTTP Framework
+ Copyright (C) Michael Justin
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+
+ You can be released from the requirements of the license by purchasing
+ a commercial license. Buying such a license is mandatory as soon as you
+ develop commercial activities involving the Daraja framework without
+ disclosing the source code of your own applications. These activities
+ include: offering paid services to customers as an ASP, shipping Daraja
+ with a closed source product.
+
+*)
+
+unit AuthResponseResource;
+
+// note: this is unsupported example code
+
+interface
+
+uses
+ djWebComponent, djTypes;
+
+type
+
+ { TAuthResponseResource }
+
+ TAuthResponseResource = class(TdjWebComponent)
+ public
+ procedure OnPost(Request: TdjRequest; Response: TdjResponse); override;
+ end;
+
+implementation
+
+uses
+ SysUtils;
+
+{ TAuthResponseResource }
+
+procedure TAuthResponseResource.OnPost(Request: TdjRequest; Response: TdjResponse);
+var
+ AccessToken: string;
+ // P: string;
+begin
+ if Request.Params.Values['state'] <> Request.Session.Content.Values['state'] then
+ begin
+ Response.ResponseNo := 401;
+ WriteLn('Invalid state parameter.');
+ Exit;
+ end;
+
+ // for P in Request.Params do
+ // begin
+ // WriteLn(P);
+ // end;
+
+ // Read the access_token
+ AccessToken := Request.Params.Values['access_token'];
+
+ Response.Session.Content.Values['access_token'] := AccessToken;
+ Response.Redirect('/index.html');
+end;
+
+end.
+
diff --git a/demo/tutorial12/MainUnit.pas b/demo/tutorial12/MainUnit.pas
new file mode 100644
index 00000000..cb4af855
--- /dev/null
+++ b/demo/tutorial12/MainUnit.pas
@@ -0,0 +1,89 @@
+(*
+
+ Daraja HTTP Framework
+ Copyright (C) Michael Justin
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+
+ You can be released from the requirements of the license by purchasing
+ a commercial license. Buying such a license is mandatory as soon as you
+ develop commercial activities involving the Daraja framework without
+ disclosing the source code of your own applications. These activities
+ include: offering paid services to customers as an ASP, shipping Daraja
+ with a closed source product.
+
+*)
+
+unit MainUnit;
+
+// note: this is unsupported example code
+
+interface
+
+procedure Demo;
+
+implementation
+
+uses
+ AuthFilter,
+ AuthResponseResource,
+ RootResource,
+ djServer, djWebAppContext, djNCSALogFilter, djWebFilterHolder,
+ ShellAPI, SysUtils;
+
+procedure Demo;
+const
+ AUTHORIZE_ENDPOINT = 'https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize';
+ // Application (client) ID from Entra configuration
+ CLIENT_ID = 'ee5a0402-2861-44a2-b0e1-d79bfafbe56a';
+ // Redirect URI must match Entra configuration
+ REDIRECT_PATH = '/auth-response';
+ REDIRECT_URI = 'http://localhost' + REDIRECT_PATH;
+var
+ Context: TdjWebAppContext;
+ FilterHolder: TdjWebFilterHolder;
+ Server: TdjServer;
+begin
+ FilterHolder := TdjWebFilterHolder.Create(TAuthFilter);
+ FilterHolder.SetInitParameter('AuthorizeEndpoint', AUTHORIZE_ENDPOINT);
+ FilterHolder.SetInitParameter('ClientID', CLIENT_ID);
+ FilterHolder.SetInitParameter('RedirectURI', REDIRECT_URI);
+
+ Context := TdjWebAppContext.Create('', True);
+ Context.AddWebComponent(TRootResource, '/index.html');
+ Context.AddWebComponent(TAuthResponseResource, REDIRECT_PATH);
+ Context.AddWebFilter(FilterHolder, '*.html');
+ Context.AddFilterWithMapping(TdjNCSALogFilter, '/*');
+
+ Server := TdjServer.Create(80);
+ try
+ try
+ Server.Add(Context);
+ Server.Start;
+
+ ShellExecute(0, 'open', PChar('http://localhost/index.html'), '', '', 0);
+
+ WriteLn('Server is running, launching web browser ...');
+ WriteLn('Hit any key to terminate.');
+ except
+ on E: Exception do WriteLn(E.Message);
+ end;
+ ReadLn;
+ finally
+ Server.Free;
+ end;
+end;
+
+end.
diff --git a/demo/tutorial12/ReadUserProfileFromMSGraph.dpr b/demo/tutorial12/ReadUserProfileFromMSGraph.dpr
new file mode 100644
index 00000000..63575731
--- /dev/null
+++ b/demo/tutorial12/ReadUserProfileFromMSGraph.dpr
@@ -0,0 +1,41 @@
+(*
+
+ Daraja HTTP Framework
+ Copyright (C) Michael Justin
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+
+ You can be released from the requirements of the license by purchasing
+ a commercial license. Buying such a license is mandatory as soon as you
+ develop commercial activities involving the Daraja framework without
+ disclosing the source code of your own applications. These activities
+ include: offering paid services to customers as an ASP, shipping Daraja
+ with a closed source product.
+
+*)
+
+program ReadUserProfileFromMSGraph;
+
+// note: this is unsupported example code
+
+{$APPTYPE CONSOLE}
+
+uses
+ MainUnit;
+
+begin
+ Demo;
+end.
+
diff --git a/demo/tutorial12/ReadUserProfileFromMSGraph.lpi b/demo/tutorial12/ReadUserProfileFromMSGraph.lpi
new file mode 100644
index 00000000..057794ef
--- /dev/null
+++ b/demo/tutorial12/ReadUserProfileFromMSGraph.lpi
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
diff --git a/demo/tutorial12/ReadUserProfileFromMSGraph.lpr b/demo/tutorial12/ReadUserProfileFromMSGraph.lpr
new file mode 100644
index 00000000..63575731
--- /dev/null
+++ b/demo/tutorial12/ReadUserProfileFromMSGraph.lpr
@@ -0,0 +1,41 @@
+(*
+
+ Daraja HTTP Framework
+ Copyright (C) Michael Justin
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+
+ You can be released from the requirements of the license by purchasing
+ a commercial license. Buying such a license is mandatory as soon as you
+ develop commercial activities involving the Daraja framework without
+ disclosing the source code of your own applications. These activities
+ include: offering paid services to customers as an ASP, shipping Daraja
+ with a closed source product.
+
+*)
+
+program ReadUserProfileFromMSGraph;
+
+// note: this is unsupported example code
+
+{$APPTYPE CONSOLE}
+
+uses
+ MainUnit;
+
+begin
+ Demo;
+end.
+
diff --git a/demo/tutorial12/RootResource.pas b/demo/tutorial12/RootResource.pas
new file mode 100644
index 00000000..81c85d55
--- /dev/null
+++ b/demo/tutorial12/RootResource.pas
@@ -0,0 +1,161 @@
+(*
+
+ Daraja HTTP Framework
+ Copyright (C) Michael Justin
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+
+ You can be released from the requirements of the license by purchasing
+ a commercial license. Buying such a license is mandatory as soon as you
+ develop commercial activities involving the Daraja framework without
+ disclosing the source code of your own applications. These activities
+ include: offering paid services to customers as an ASP, shipping Daraja
+ with a closed source product.
+
+*)
+
+unit RootResource;
+
+// note: this is unsupported example code
+
+interface
+
+uses
+ djWebComponent, djTypes;
+
+type
+
+ { TRootResource }
+
+ TRootResource = class(TdjWebComponent)
+ private
+ function ReadUserProfile(const AccessToken: string): string;
+ function SendMail(const AccessToken: string): string;
+ public
+ procedure OnGet(Request: TdjRequest; Response: TdjResponse); override;
+ end;
+
+implementation
+
+uses
+ {$IFDEF FPC}{$NOTES OFF}{$ENDIF}{$HINTS OFF}{$WARNINGS OFF}
+ IdHTTP, IdSSLOpenSSL, IdSSLOpenSSLHeaders,
+ {$IFDEF FPC}{$ELSE}{$HINTS ON}{$WARNINGS ON}{$ENDIF}
+ SysUtils, Classes;
+
+function CreateIdHTTPwithSSL12(const AccessToken: string): TIdHTTP;
+var
+ IOHandler: TIdSSLIOHandlerSocketOpenSSL;
+begin
+ Result := TIdHTTP.Create;
+
+ IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(Result);
+ IOHandler.SSLOptions.SSLVersions := [sslvTLSv1_2];
+ Result.IOHandler := IOHandler;
+
+ Result.Request.CustomHeaders.Values['Authorization'] := 'Bearer ' + AccessToken;
+end;
+
+{ TRootResource }
+
+procedure TRootResource.OnGet(Request: TdjRequest; Response: TdjResponse);
+var
+ AccessToken: string;
+ APIResponse: string;
+begin
+ AccessToken := Request.Session.Content.Values['access_token'];
+
+ APIResponse := ReadUserProfile(AccessToken);
+
+ SendMail(AccessToken);
+
+ Response.ContentText := Format('
Graph API example
'
+ + 'Signed-in user profile:
%s
'
+ + 'Send email:
Email has been sent.
',
+ [APIResponse]);
+ Response.ContentType := 'text/html';
+ Response.CharSet := 'utf-8';
+end;
+
+function TRootResource.ReadUserProfile(const AccessToken: string): string;
+var
+ HTTP: TIdHTTP;
+begin
+ HTTP := CreateIdHTTPwithSSL12(AccessToken);
+ try
+ try
+ Result := HTTP.Get('https://graph.microsoft.com/v1.0/users/me');
+ except
+ WriteLn(IdSSLOpenSSLHeaders.WhichFailedToLoad);
+ raise;
+ end;
+ finally
+ HTTP.Free;
+ end;
+end;
+
+function TRootResource.SendMail(const AccessToken: string): string;
+const
+ JSON =
+ '{'+ #10
+ +' "message": {'+ #10
+ +' "subject": "Meet for lunch?",'+ #10
+ +' "body": {'+ #10
+ +' "contentType": "Text",'+ #10
+ +' "content": "The new cafeteria is open."'+ #10
+ +' },'+ #10
+ +' "toRecipients": ['+ #10
+ +' {'+ #10
+ +' "emailAddress": {'+ #10
+ +' "address": "info@habarisoft.com"'+ #10
+ +' }'+ #10
+ +' }'+ #10
+ +' ]'+ #10
+ +' },'+ #10
+ +' "saveToSentItems": "false"'+ #10
+ +'}';
+var
+ HTTP: TIdHTTP;
+ RequestBody: TStream;
+ ResponseBody: string;
+begin
+ // WriteLn(JSON);
+
+ HTTP := CreateIdHTTPwithSSL12(AccessToken);
+ try
+ try
+ HTTP.Request.ContentType := 'application/json';
+ RequestBody := TStringStream.Create(JSON, TEncoding.UTF8);
+ ResponseBody := HTTP.Post('https://graph.microsoft.com/v1.0/me/sendMail', RequestBody);
+ // WriteLn('Response: "' + ResponseBody + '"');
+ except
+ on E: EIdHTTPProtocolException do
+ begin
+ WriteLn(E.Message);
+ WriteLn(E.ErrorMessage);
+ raise;
+ end;
+ on E: Exception do
+ begin
+ WriteLn(E.Message);
+ raise;
+ end;
+ end;
+ finally
+ HTTP.Free;
+ end;
+end;
+
+end.