<cfcomponent displayname="oAuth" output="true" hint="FAX oAuth 2.0 credential authentication">
	
	<cffunction name="GetAccessToken" returntype="any" displayName="Get oAuth Access Token" description="I check cache for token, return if found. Otherwise, I perform oAuth 2.0 credential authentication and set credentials into Cache and return for use" access="public" output="false" hint="This oAuth call is for the Fax service">
		<cfargument required="false" type="numeric" name="OauthServerCallTimeOuts" 	displayname="Oauth Server Call Time Out" 	default="" 	hint="Application variable - Time in seconds before timing out"/>
		<cfargument required="false" type="string"  name="TheClientID" 				displayname="The Client ID" 				default="" 	hint="Application variable - Used for authorization"/>
		<cfargument required="false" type="string" 	name="TheClientSecret" 			displayname="The Client Secret" 			default="" 	hint="Application variable - Used for authorization"/>
		<cfargument required="false" type="string" 	name="OauthTokenEndpoint" 		displayname="Oauth Token Endpoint" 			default="" 	hint="Application variable - URL used to access ther oAuth Server"/>
		<cfargument required="false" type="string" 	name="OauthGrantType" 			displayname="Oauth Grant Type" 				default="" 	hint="Application variable - Used for authorization"/>

		<!--- Intialize function and oAuth Server Response Parameters --->
		<cfset LOCAL.TheReturnedData			= "">	
		<cfset LOCAL.TheAccessToken				= "">
		<cfset LOCAL.TheExpiration			    = "">
		<cfset LOCAL.returnResult               = StructNew()>
		<cfset LOCAL.returnResult.ErrorMessage  = "">
		<cfset LOCAL.returnResult.ValidToken 	= "">
		
		<!--- ================= START: CHECK COLD FUSION CACHE FOR VALID AUTH ACCESS TOKEN =================== --->
		
		<!--- Check CF memory for valid cached access token --->
		<cfif arrayFindNoCase(cacheGetAllIds(), "TheFaxToken")>
			
			<!--- If Access Token exists in cache, set valid token for return --->
			<cfset LOCAL.returnResult.ValidToken = cacheGet("TheFaxToken")>
			
			<!--- Return Access Token --->
			<cfreturn LOCAL.returnResult />
		
		</cfif>
		<!--- ================= END: CHECK COLD FUSION CACHE FOR VALID AUTH ACCESS TOKEN =================== --->
	
		
		<!--- ================= START: AUTH SERVICE CALL FOR OBTAINING A VALID ACCESS TOKEN =================== --->
		
		<!--- Build complete Oauth Token Endpoint for submission.
			  Enpoint consists of URL to oAuth server and any required URL parameters. --->
		<cfset LOCAL.TheOauthTokenEndpoint = ARGUMENTS.OauthTokenEndpoint & "?grant_type=#URLEncodedFormat(ARGUMENTS.OauthGrantType)#">

		<!--- Construct the "Authorization" header parameter for Oauth server call. 
			  Combine Client ID/Password in the specific format (client_id:client_password).
			  base64urlEncode them and prepend the word "Basic" to create a valid formatted value --->
		<cfset LOCAL.TheEncodedValueToPass 	= ARGUMENTS.TheClientID & ":" & ARGUMENTS.TheClientSecret>		
		<cfset LOCAL.TheEncodedValueToPass 	= "Basic #ToBase64(LOCAL.TheEncodedValueToPass)#">
		
		<!--- Make a call to the Oauth server to obtain the access token and payload --->
		<cfset LOCAL.OauthStartTime = GetTickCount()>
		<cfhttp 
			url		= "#LOCAL.TheOauthTokenEndpoint#" 
			method	= "POST" 
			timeout	= "#ARGUMENTS.OauthServerCallTimeOuts#" 
			result	= "httpResponse">
	
			<cfhttpparam name="Content-Type" 	type="HEADER" value="application/x-www-form-urlencoded">
			<cfhttpparam name="Authorization" 	type="HEADER" value="#LOCAL.TheEncodedValueToPass#">
		</cfhttp>
		<cfset LOCAL.OauthEndTime = GetTickCount()>
		
		
		<!--- error check the Oauth server call --->
		<cfif LEN(TRIM(httpResponse.Filecontent)) NEQ 0>
			
			<cftry>
				<!--- verify JSON format and Deserialize --->
				<cfif isJSON(httpResponse.fileContent)>
					
					<cfset LOCAL.TheReturnedData 	= DeserializeJSON(#httpResponse.fileContent#)>
					
					<!--- Format Access Token --->
					<!--- The token type "Bearer" needs prepended for creating a valid formatted token --->
					<cfset LOCAL.TheAccessToken 	= StructFind(LOCAL.TheReturnedData, "access_token")>
					<cfset LOCAL.TheAccessToken 	= "Bearer #LOCAL.TheAccessToken#">
					
					<!--- Format Epiration --->
					<!--- the expiration is converted from milliseconds into seconds, 
						  and five seconds is subtracted to ensure enough processing time to complete any service requests --->
					<cfset LOCAL.TheExpiration 		= StructFind(LOCAL.TheReturnedData, "expires_in")>
					<cfset LOCAL.TheExpiration 		= #fix(#LOCAL.TheExpiration#/1000)#>
					<cfset LOCAL.TheExpiration 		= #LOCAL.TheExpiration#-5>
					
					<!--- set access token into cache with expiration, save in the return variable --->
					<cfcache action="PUT" name="ValidoAuthAccessToken" value="#LOCAL.TheAccessToken#" id="TheFaxToken" timespan="#CreateTimeSpan(0, 0, 0, LOCAL.TheExpiration)#">
					<cfset LOCAL.returnResult.ValidToken = #LOCAL.TheAccessToken#>
				
				</cfif>
				<cfcatch>
					<!--- ERROR: add general CFCATCH error to error log statement --->
					<cfset LOCAL.returnResult.ErrorMessage = LOCAL.returnResult.ErrorMessage & "OAUTH SERVER: Error capturing/formatting/setting access token|CFCATCH MESSAGE: #CFCATCH.Message#|CFCATCH DETAIL: #CFCATCH.Detail#|HTTP RESPONSE: #httpResponse.fileContent#|CFC FILE: oAuth.cfc|FUNCTION: GetAccessToken">
				</cfcatch>
			</cftry>
		<cfelse>
			<!--- ERROR: add failed Oauth call to error log statement --->
			<cfset LOCAL.oAuthRunningTime 	 	   = NumberFormat((LOCAL.OauthEndTime - LOCAL.OauthStartTime)/1000,'__.___')>
			<cfset LOCAL.returnResult.ErrorMessage = LOCAL.returnResult.ErrorMessage & "OAUTH SERVER: Error no response returned from server|EXECUTION TIME: #LOCAL.oAuthRunningTime# milleseconds|CFC FILE: oAuth.cfc|FUNCTION: GetAccessToken">
		</cfif>
		
		<!--- Return Results --->
		<cfreturn LOCAL.returnResult />
	</cffunction>
</cfcomponent>

