Repository URL to install this package:
|
Version:
3.2.0 ▾
|
{ **********************************************************************
This file is part of the Free Component Library (FCL)
Copyright (c) 2015 by the Free Pascal development team
OAuth2 web request handler classes
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
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.
**********************************************************************}
unit fpoauth2;
{$mode objfpc}{$H+}
interface
uses
Typinfo,Classes, SysUtils, fpjson, fpjwt, fpwebclient;
Type
{ TOAuth2Config }
TAccessType = (atOnline,atOffline);
TAbstracTOAuth2ConfigStore = Class;
EOAuth2 = Class(Exception);
{ TOAuth2Config }
{ TJWTIDToken }
TJWTIDToken = Class(TJWT)
private
FClaimsClass: TClaimsClass;
FJOSEClass: TJOSEClass;
Protected
Function CreateClaims : TClaims; override;
Function CreateJOSE : TJOSE; override;
Property ClaimsClass: TClaimsClass Read FClaimsClass;
Property JOSEClass: TJOSEClass Read FJOSEClass;
Public
// Pass on the actual Claims/JOSE class to be used. When Nil, defaults are used.
Constructor CreateWithClasses(AClaims: TClaimsClass; AJOSE : TJOSEClass);
// Extract a unique user ID from the claims. By default, this calls GetUniqueUserName
Function GetUniqueUserID : String; virtual;
// Extract a unique user name from the claims. Must be overridden by descendents.
Function GetUniqueUserName : String; virtual;
// Extract a user display name from the claims. By default, this calls GetUniqueUserName
Function GetUserDisplayName : String; virtual;
end;
// OAuth2 client and server settings.
TOAuth2Config = Class(TPersistent)
private
FAuthScope: String;
FAuthURL: String;
FClientID: String;
FClientSecret: String;
FRedirectURI: String;
FDeveloperKey: String;
FHostedDomain: String;
FIncludeGrantedScopes: Boolean;
FOpenIDRealm: String;
FTokenURL: String;
FAccessType: TAccessType;
Protected
Public
Procedure Assign(Source : TPersistent); override;
Procedure SaveToStrings(L : TStrings);
Published
//
// Local OAuth2 client config part.
//
Property ClientID : String Read FClientID Write FClientID;
Property ClientSecret : String Read FClientSecret Write FClientSecret;
Property RedirectURI : String Read FRedirectURI Write FRedirectURI;
Property AccessType : TAccessType Read FAccessType Write FAccessType;
// Specific for google.
Property DeveloperKey : String Read FDeveloperKey Write FDeveloperKey;
Property OpenIDRealm : String Read FOpenIDRealm Write FOpenIDRealm;
//
// Auth Provider part
//
// Domain part, can be substituted on URL to refresh access token
Property HostedDomain : String Read FHostedDomain Write FHostedDomain;
// URL to authenticate a user. used in creating the redirect URL. Can contain %HostedDomain%
Property AuthURL: String Read FAuthURL Write FAuthURL;
// URL To exchange authorization code for access token. Can contain %HostedDomain%
Property TokenURL: String Read FTokenURL Write FTokenURL;
// Authorized Scopes (Google parlance) or resources (Microsoft parlance)
Property AuthScope: String Read FAuthScope Write FAuthScope;
// Google specific: adds AuthScope to existing scopes (incremental increase of authorization).
Property IncludeGrantedScopes : Boolean Read FIncludeGrantedScopes Write FIncludeGrantedScopes;
end;
TOAuth2ConfigClass = Class of TOAuth2Config;
{ TOAuth2Session }
//
// User config part
//
TOAuth2Session = Class(TPersistent)
Private
FRefreshToken: String;
FLoginHint: String;
FIDToken: String;
FState: String;
FAccessToken: String;
FAuthTokenType: String;
FAuthCode: String;
FAuthExpires: TDateTime;
FAuthExpiryPeriod: Integer;
procedure SetAuthExpiryPeriod(AValue: Integer);
Protected
Class Function AuthExpiryMargin : Integer; virtual;
procedure DoLoadFromJSON(AJSON: TJSONObject); virtual;
Public
Procedure LoadTokensFromJSONResponse(Const AJSON : String);
Procedure LoadStartTokensFromVariables(Const Variables : TStrings);
Procedure SaveToStrings(L : TStrings);
procedure Assign(Source: TPersistent); override;
Published
// Authentication code received at the first step of the OAuth2 sequence
Property AuthCode: String Read FAuthCode Write FAuthCode;
// Access token to be used for authorized scopes. Received in step 2 of the OAuth2 sequence;
Property AccessToken: String Read FAccessToken Write FAccessToken;
// Refresh token to renew Access token. received in step 2 of the OAuth2 sequence;
Property RefreshToken : String Read FRefreshToken Write FRefreshToken;
// When does the authentication end, local time.
Property AuthExpires : TDateTime Read FAuthExpires Write FAuthExpires;
// Seconds till access token expires. Setting this will set the AuthExpires property to Now+(AuthExpiryPeriod-AuthExpiryMargin)
Property AuthExpiryPeriod : Integer Read FAuthExpiryPeriod Write SetAuthExpiryPeriod;
// Token type (Bearer)
Property AuthTokenType: String Read FAuthTokenType Write FAuthTokenType;
// State, saved as part of the user config.
Property State : String Read FState Write FState;
// Login hint
Property LoginHint : String Read FLoginHint Write FLoginHint;
// IDToken
Property IDToken : String Read FIDToken Write FIDToken;
end;
TOAuth2SessionClass = Class of TOAuth2Session;
TAbstractOAuth2ConfigStore = CLass(TComponent)
Public
Procedure SaveConfig(AConfig : TOAuth2Config); virtual; abstract;
Procedure LoadConfig(AConfig : TOAuth2Config); virtual; abstract;
Procedure SaveSession(ASession : TOAuth2Session; Const AUser : String); virtual; abstract;
Procedure LoadSession(ASession : TOAuth2Session; Const AUser : String); virtual; abstract;
end;
TAbstractOAuth2ConfigStoreClass = Class of TAbstractOAuth2ConfigStore;
TUserConsentHandler = Procedure (Const AURL : String; Out AAuthCode : String) of object;
TOnAuthConfigChangeHandler = Procedure (Const Sender : TObject; Const AConfig : TOAuth2Config) of object;
TOnAuthSessionChangeHandler = Procedure (Const Sender : TObject; Const ASession : TOAuth2Session) of object;
TOnIDTokenChangeHandler = Procedure (Const Sender : TObject; Const AToken : TJWTIDToken) of object;
TSignRequestHandler = Procedure (Const Sender : TObject; Const ARequest : TWebClientRequest)of object;
TAuthenticateAction = (aaContinue,aaRedirect,aaFail);
{ TOAuth2Handler }
TOAuth2Handler = Class(TAbstractRequestSigner)
private
FAutoConfig: Boolean;
FAutoSession: Boolean;
FConfigLoaded: Boolean;
FSessionLoaded: Boolean;
FClaimsClass: TClaimsClass;
FConfig: TOAuth2Config;
FSession: TOAuth2Session;
FIDToken: TJWTIDToken;
FWebClient: TAbstractWebClient;
FStore : TAbstracTOAuth2ConfigStore;
FOnAuthSessionChange: TOnAuthSessionChangeHandler;
FOnIDTokenChange: TOnIDTokenChangeHandler;
FOnSignRequest: TOnAuthConfigChangeHandler;
FOnAuthConfigChange: TOnAuthConfigChangeHandler;
FOnUserConsent: TUserConsentHandler;
Function GetAutoStore : Boolean;
Procedure SetAutoStore(AValue : Boolean);
procedure SetConfig(AValue: TOAuth2Config);
procedure SetSession(AValue: TOAuth2Session);
procedure SetStore(AValue: TAbstracTOAuth2ConfigStore);
Protected
function CheckHostedDomain(URL: String): String; virtual;
Function RefreshToken: Boolean; virtual;
Function CreateOauth2Config : TOAuth2Config; virtual;
Function CreateOauth2Session : TOAuth2Session; virtual;
Function CreateIDToken : TJWTIDToken; virtual;
Procedure Notification(AComponent: TComponent; Operation: TOperation); override;
Procedure DoAuthConfigChange; virtual;
Procedure DoAuthSessionChange(Const AUser : String = ''); virtual;
Procedure DoSignRequest(ARequest: TWebClientRequest); override;
Property ConfigLoaded : Boolean Read FConfigLoaded;
Property SessionLoaded : Boolean Read FSessionLoaded;
Public
Class Var DefaultConfigClass : TOAuth2ConfigClass;
Class Var DefaultSessionClass : TOAuth2SessionClass;
Public
Constructor Create(AOwner : TComponent);override;
Destructor Destroy; override;
// Variable name for AuthScope in authentication URL.
// Default = scope. Descendents can override this to provide correct behaviour.
Class Function AuthScopeVariableName : String; virtual;
// Default for hosted domain, if any
Class function DefaultHostedDomain: String; virtual;
// Check if config is authenticated.
Function IsAuthenticated : Boolean; virtual;
// Generate an authentication URL
Function AuthenticateURL : String; virtual;
// Check what needs to be done for authentication.
// Do whatever is necessary to mark the request as 'authenticated'.
Function Authenticate: TAuthenticateAction; virtual;
// Load config from store
procedure LoadConfig(Force : Boolean = false);
// Save config to store
procedure SaveConfig;
// Load Session from store.If AUser is empty, then ID Token.GetUniqueUser is used.
procedure LoadSession(Const AUser : String = ''; AForce : Boolean = False);
// Save session in store. If AUser is empty, then ID Token.GetUniqueUser is used. Will call OnAuthSessionChange
procedure SaveSession(Const AUser : String = '');
// Refresh ID token from Session.IDToken. Called after token is refreshed or session is loaded.
// This will change the actual IDToken instance.
procedure RefreshIDToken;
// This is populated from Config.IDToken if it is not empty. Do not cache this instance. It is recreated after a call to RefreshIDToken
Property IDToken : TJWTIDToken Read FIDToken;
// Set this to initialize the claims for the ID token. By default, it is TClaims
Property ClaimsClass : TClaimsClass Read FClaimsClass Write FClaimsClass;
Published
// Must be set prior to calling
Property Config : TOAuth2Config Read FConfig Write SetConfig;
// Session info.
Property Session : TOAuth2Session Read FSession Write SetSession;
// Webclient used to do requests to authorization service
Property WebClient : TAbstractWebClient Read FWebClient Write FWebClient;
// Event handler to get user consent if no access token or refresh token is available
Property OnUserConsent : TUserConsentHandler Read FOnUserConsent Write FOnUserConsent;
// Called when the auth config informaion changes
Property OnAuthConfigChange : TOnAuthConfigChangeHandler Read FOnAuthConfigChange Write FOnAuthConfigChange;
// Called when the auth sesson information changes
Property OnAuthSessionChange : TOnAuthSessionChangeHandler Read FOnAuthSessionChange Write FOnAuthSessionChange;
// Called when the IDToken information changes
Property OnIDTokenChange : TOnIDTokenChangeHandler Read FOnIDTokenChange Write FOnIDTokenChange;
// Called when a request is signed
Property OnSignRequest : TOnAuthConfigChangeHandler Read FOnSignRequest Write FOnSignRequest;
// User to load/store parts of the config store.
Property Store : TAbstracTOAuth2ConfigStore Read FStore Write SetStore;
// Call storing session/config automatically when needed.
Property AutoStore : Boolean Read GetAutoStore Write SetAutoStore;
// AutoSession = True makes sure the load/save of the session as needed.
Property AutoSession : Boolean Read FAutoSession Write FAutoSession default True;
// AutoConfig = True will enable the load of config as needed.
Property AutoConfig : Boolean Read FAutoConfig Write FAutoConfig default True;
end;
TOAuth2HandlerClass = Class of TOAuth2Handler;
implementation
uses httpdefs;
Resourcestring
SErrFailedToRefreshToken = 'Failed to refresh access token: Status %d, Error: %s';
{ TOAuth2Handler }
{ Several possibilities:
1. Acess token is available.
A) Access token is not yet expired
-> All is well, continue.
B) Access token is available, but is expired.
Refresh token is
i) Available
-> get new access token using refresh token.
(may fail -> fail)
ii) Not available
-> error.
3. No access token is available.
A) Offline
-> Need to get user consent using callback.
i) User consent results in Access token (AConfig.AuthToken)
-> Auth token is exchanged for a refresh token & access token
ii) User consent failed or no callback.
-> Fail
B) Online: Need to redirect to get access token and auth token.
}
{ TTWTIDToken }
constructor TJWTIDToken.CreateWithClasses(AClaims: TClaimsClass;
AJOSE: TJOSEClass);
begin
FClaimsClass:=AClaims;
FJOSEClass:=AJOSE;
Inherited Create;
end;
function TJWTIDToken.GetUniqueUserID: String;
begin
Result:=GetUniqueUserName;
end;
function TJWTIDToken.GetUniqueUserName: String;
begin
Result:='';
end;
function TJWTIDToken.GetUserDisplayName: String;
begin
Result:=GetUniqueUserName;
end;
function TJWTIDToken.CreateClaims: TClaims;
begin
if FClaimsClass=Nil then
Result:=Inherited CreateClaims
else
Result:=FClaimsClass.Create;
end;
function TJWTIDToken.CreateJOSE: TJOSE;
begin
if FJOSEClass=Nil then
Result:=Inherited CreateJOSE
else
Result:=FJOSEClass.Create;
end;
function TOAuth2Handler.Authenticate: TAuthenticateAction;
Var
S : String;
begin
if IsAuthenticated then
result:=aaContinue
else
Case Config.AccessType of
atonline :
Result:=aaRedirect; // we need to let the user authenticate himself.
atoffline :
if Not Assigned(FOnUserConsent) then
result:=aaFail
else
begin
FOnUserConsent(AuthenticateURL,S);
Session.AuthCode:=S;
// Exchange authcode for access code.
if IsAuthenticated then
result:=aaContinue
else
result:=aaFail
end;
end;
end;
function TOAuth2Handler.CheckHostedDomain(URL : String): String;
Var
HD : String;
begin
HD:=Config.HostedDomain;
if (HD='') then
Result:=DefaultHostedDomain;
Result:=StringReplace(URL,'%HostedDomain%',Config.HostedDomain,[rfIgnoreCase]);
end;
Class function TOAuth2Handler.DefaultHostedDomain : String;
begin
Result:='';
end;
function TOAuth2Handler.AuthenticateURL: String;
begin
Result:=Config.AuthURL
+ '?'+ AuthScopeVariableName+'='+HTTPEncode(Config.AuthScope)
+'&redirect_uri='+HTTPEncode(Config.RedirectUri)
+'&client_id='+HTTPEncode(Config.ClientID)
+'&response_type=code'; // Request refresh token.
Result:=CheckHostedDomain(Result);
if Assigned(Session) then
begin
if (Session.LoginHint<>'') then
Result:=Result +'&login_hint='+HTTPEncode(Session.LoginHint);
if (Session.State<>'') then
Result:=Result +'&state='+HTTPEncode(Session.State);
end;
end;
procedure TOAuth2Handler.SetConfig(AValue: TOAuth2Config);
begin
if FConfig=AValue then Exit;
FConfig.Assign(AValue);
end;
procedure TOAuth2Handler.SetSession(AValue: TOAuth2Session);
begin
if FSession=AValue then Exit;
FSession.Assign(AValue);
end;
procedure TOAuth2Handler.LoadConfig(Force : Boolean = False);
begin
if Assigned(Store) then
if Force or not ConfigLoaded then
begin
Store.LoadConfig(Config);
FConfigLoaded:=True;
end;
end;
procedure TOAuth2Handler.SaveConfig;
begin
if Assigned(Store) then
begin
Store.SaveConfig(Config);
FConfigLoaded:=True;
end;
end;
procedure TOAuth2Handler.LoadSession(const AUser: String; AForce : Boolean = False);
Var
U : String;
begin
if Assigned(Store) then
if AForce or Not SessionLoaded then
begin
U:=AUser;
If (U='') and Assigned(FIDToken) then
U:=FIDToken.GetUniqueUserID;
Store.LoadSession(Session,AUser);
FSessionLoaded:=True;
if (Session.IDToken<>'') then
RefreshIDToken;
end;
end;
procedure TOAuth2Handler.SaveSession(const AUser: String);
Var
U : String;
begin
if Assigned(FOnAuthSessionChange) then
FOnAuthSessionChange(Self,Session);
if Assigned(Store) then
begin
Store.SaveSession(Session,AUser);
FSessionLoaded:=True;
end;
end;
Function TOAuth2Handler.GetAutoStore : Boolean;
begin
Result:=AutoSession and AutoConfig;
end;
Procedure TOAuth2Handler.SetAutoStore(AValue : Boolean);
begin
AutoSession:=True;
AutoConfig:=True;
end;
procedure TOAuth2Handler.RefreshIDToken;
begin
FreeAndNil(FIDToken);
if (Session.IDToken<>'') then
begin
FIDtoken:=CreateIDToken;
FIDToken.AsEncodedString:=Session.IDToken;
If Assigned(FOnIDTokenChange) then
FOnIDTokenChange(Self,FIDToken);
end;
end;
function TOAuth2Handler.RefreshToken: Boolean;
Var
URL,Body : String;
D : TJSONData;
Req: TWebClientRequest;
Resp: TWebClientResponse;
begin
if AutoConfig and not ConfigLoaded then
LoadConfig;
Req:=Nil;
Resp:=Nil;
D:=Nil;
try
Req:=WebClient.CreateRequest;
Req.Headers.Values['Content-Type']:='application/x-www-form-urlencoded';
url:=CheckHostedDomain(Config.TOKENURL);
Body:='client_id='+HTTPEncode(Config.ClientID)+
'&client_secret='+ HTTPEncode(Config.ClientSecret);
if (Session.RefreshToken<>'') then
body:=Body+'&refresh_token='+HTTPEncode(Session.RefreshToken)+
'&grant_type=refresh_token'
else
begin
body:=Body+
'&grant_type=authorization_code'+
'&redirect_uri='+HTTPEncode(Config.RedirectUri)+
'&code='+HTTPEncode(Session.AuthCode);
end;
Req.SetContentFromString(Body);
Resp:=WebClient.ExecuteRequest('POST',url,Req);
Result:=(Resp.StatusCode=200);
if Result then
begin
Session.LoadTokensFromJSONResponse(Resp.GetContentAsString);
If (Session.IDToken<>'') then
begin
RefreshIDToken;
if AutoSession then
DoAuthSessionChange(IDToken.GetUniqueUserName);
end;
end
else
Raise EOAuth2.CreateFmt(SErrFailedToRefreshToken,[Resp.StatusCode,Resp.StatusText]);
Result:=True;
finally
D.Free;
Resp.Free;
Req.Free;
end;
end;
function TOAuth2Handler.CreateOauth2Config: TOAuth2Config;
begin
Result:=DefaultConfigClass.Create;
end;
function TOAuth2Handler.CreateOauth2Session: TOAuth2Session;
begin
Result:=DefaultSessionClass.Create;
end;
function TOAuth2Handler.CreateIDToken: TJWTIDToken;
begin
Result:=TJWTIDToken.CreateWithClasses(ClaimsClass,Nil);
end;
procedure TOAuth2Handler.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation=opRemove) then
if AComponent=FStore then
FStore:=Nil;
end;
function TOAuth2Handler.IsAuthenticated: Boolean;
begin
If AutoConfig then
LoadConfig;
// See if we need to load the session
if (Session.RefreshToken='') and AutoSession then
LoadSession;
Result:=(Session.AccessToken<>'');
If Result then
// have access token. Check if it is still valid.
begin
// Not expired ?
Result:=(Now<Session.AuthExpires);
// Expired, but have refresh token ?
if (not Result) and (Session.RefreshToken<>'') then
Result:=RefreshToken;
end
else if (Session.RefreshToken<>'') then
begin
// No access token, but have refresh token
Result:=RefreshToken;
end
else if (Session.AuthCode<>'') then
// No access or refresh token, but have auth code.
Result:=RefreshToken;
end;
{ TOAuth2Handler }
procedure TOAuth2Handler.DoAuthConfigChange;
begin
If Assigned(FOnAuthConfigChange) then
FOnAuthConfigChange(Self,Config);
SaveConfig;
end;
procedure TOAuth2Handler.DoAuthSessionChange(Const AUser : String = '');
begin
If Assigned(FOnAuthSessionChange) then
FOnAuthSessionChange(Self,Session);
SaveSession(AUser);
end;
procedure TOAuth2Handler.DoSignRequest(ARequest: TWebClientRequest);
Var
TT,AT : String;
begin
if Authenticate=aaContinue then
begin
TT:=Session.AuthTokenType;
AT:=Session.AccessToken;
Arequest.Headers.Add('Authorization: '+TT+' '+HTTPEncode(AT));
end
else
Raise EOAuth2.Create('Cannot sign request: not authorized');
end;
constructor TOAuth2Handler.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FConfig:=CreateOauth2Config;
FSession:=CreateOauth2Session;
FAutoSession:=True;
FAutoConfig:=True;
end;
destructor TOAuth2Handler.Destroy;
begin
FreeAndNil(FIDToken);
FreeAndNil(FConfig);
FreeAndNil(FSession);
inherited Destroy;
end;
class function TOAuth2Handler.AuthScopeVariableName: String;
begin
Result:='scope';
end;
{ TOAuth2Config }
procedure TOAuth2Handler.SetStore(AValue: TAbstracTOAuth2ConfigStore);
begin
if FStore=AValue then Exit;
if Assigned(FStore) then
FStore.RemoveFreeNotification(Self);
FStore:=AValue;
if Assigned(FStore) then
FStore.FreeNotification(Self);
end;
class function TOAuth2Session.AuthExpiryMargin: Integer;
begin
Result:=10;
end;
procedure TOAuth2Session.SetAuthExpiryPeriod(AValue: Integer);
begin
if FAuthExpiryPeriod=AValue then Exit;
FAuthExpiryPeriod:=AValue;
AuthExpires:=Now+AValue/SecsPerDay;
end;
procedure TOAuth2Config.Assign(Source: TPersistent);
Var
C : TOAuth2Config;
begin
if Source is TOAuth2Config then
begin
C:=Source as TOAuth2Config;
FAuthURL:=C.AuthURL;
FTokenURL:=C.TokenURL;
FClientID:=C.ClientID;
FClientSecret:=C.ClientSecret;
FRedirectURI:=C.RedirectURI;
FAccessType:=C.AccessType;
FDeveloperKey:=C.DeveloperKey;
FHostedDomain:=C.HostedDomain;
FIncludeGrantedScopes:=C.IncludeGrantedScopes;
FOpenIDRealm:=C.OpenIDRealm;
FAuthScope:=C.AuthScope;
end
else
inherited Assign(Source);
end;
procedure TOAuth2Config.SaveToStrings(L: TStrings);
Procedure W(N,V : String);
begin
L.Add(N+'='+V);
end;
begin
W('AuthURL',AuthURL);
W('TokenURL',TokenURL);
W('ClientID',ClientID);
W('ClientSecret',ClientSecret);
W('RedirectURI',RedirectURI);
W('AccessType',GetEnumName(TypeInfo(TAccessType),Ord(AccessType)));
W('DeveloperKey',DeveloperKey);
W('HostedDomain',HostedDomain);
W('IncludeGrantedScopes',BoolToStr(IncludeGrantedScopes,True));
W('OpenIDRealm',OpenIDRealm);
W('AuthScope',AuthScope);
end;
procedure TOAuth2Session.SaveToStrings(L: TStrings);
Procedure W(N,V : String);
begin
L.Add(N+'='+V);
end;
begin
W('AuthCode',AuthCode);
W('RefreshToken',RefreshToken);
W('LoginHint',LoginHint);
W('IDToken',IDToken);
W('AccessToken',AccessToken);
W('AuthExpiryPeriod',IntToStr(AuthExpiryPeriod));
W('AuthExpires',DateTimeToStr(AuthExpires));
W('State',State);
W('AuthTokenType',AuthTokenType);
end;
procedure TOAuth2Session.Assign(Source: TPersistent);
Var
C : TOAuth2Session;
begin
if Source is TOAuth2Session then
begin
C:=Source as TOAuth2Session;
FAuthCode:=C.AuthCode;
FRefreshToken:=C.RefreshToken;
FLoginHint:=C.LoginHint;
FIDToken:=C.IDToken;
FAccessToken:=C.AccessToken;
FAuthExpiryPeriod:=C.AuthExpiryPeriod;
FAuthExpires:=C.AuthExpires;
FState:=C.State;
FAuthTokenType:=C.AuthTokenType;
end
else
inherited Assign(Source);
end;
procedure TOAuth2Session.DoLoadFromJSON(AJSON: TJSONObject);
Function Get(Const AName,ADefault : String) : String;
begin
Result:=AJSON.Get(AName,ADefault);
end;
Var
i : Integer;
begin
AccessToken:=Get('access_token',AccessToken);
RefreshToken:=Get('refresh_token',RefreshToken);
AuthTokenType:=Get('token_type',AuthTokenType);
IDToken:=Get('id_token',IDToken);
// Microsoft sends expires_in as String !!
I:=AJSON.IndexOfName('expires_in');
if (I<>-1) then
begin
I:=AJSON.Items[i].AsInteger;
if (I>0) then
AuthExpiryPeriod:=I;
end;
end;
procedure TOAuth2Session.LoadTokensFromJSONResponse(const AJSON: String);
Var
D : TJSONData;
begin
D:=GetJSON(AJSON);
try
DoLoadFromJSON(D as TJSONObject);
finally
D.Free;
end;
end;
procedure TOAuth2Session.LoadStartTokensFromVariables(const Variables: TStrings);
Function Get(Const AName,ADefault : String) : String;
Var
I : Integer;
begin
I:=Variables.IndexOfName(AName);
if I=-1 then
Result:=ADefault
else
Result:=Variables.ValueFromIndex[i];
end;
begin
AuthCode:=Get('code',AuthCode);
LoginHint:=Get('login_hint',LoginHint);
end;
initialization
TOAuth2Handler.DefaultConfigClass:=TOAuth2Config;
TOAuth2Handler.DefaultSessionClass:=TOAuth2Session;
end.