ISAM OAuth Inactivity

Its not immediately obvious, and commonly misconstrued as an problem of disappearing tokens, but the OAuth grants in ISAM have a “Maximum” Grant lifetime, as opposed to an inactivity in a default API Definition.

This means that when you request a Token – say via ROPC and you are using the default settings of an API Definition, regardless of how many times you use the token, how many times you refresh the token, or when you refresh the token, it will get cleaned up in exactly 7 days (604,800 seconds) after the grant was issued.

So the first step, is to likely increase this, 7 days isn’t particularly long in most deployments.

The next thing, is to configure inactivity based timeouts, or rather, extend the lifetime of the grant, when a refresh is performed.This can be done with the OAuth Mapping rule, and there is an existing example for modifying a tokens lifetime in the mapping rule (Custom lifetimes per client id), that can be slightly tweaked to perform inactivity.

The crux of it is to simply update the refresh tokens lifetime on refresh, (it would typically have a reducing lifetime, equal to 7 days minus the elapsed time). And we could leave it there.  (With the key part shown in Red and bold).

The slightly extended piece of code below however also updates the access token timeout in the event that the refresh is occurring in the window where the grant lifetime is less than the access token lifetime (for example a refresh occurring within in the last 10 minutes – would result in the access token having a reduced lifetime too). So, this code updates it too when required – such that it would be returned to the default of 60 minutes (3600 seconds) and the JSON response updated to reflect this.

 


/** Token Update demo
 *
 * The following is a demo which shows how a token can be updated to change its
 * expiry. 
 *
 */
var activitylifetimeupdate = true;
if(activitylifetimeupdate) {
	var temp_attr = null;
	/*
	 * Check its a request to /token.
	 */
	if (grant_type == "refresh_token") {
		/*
		 * Extract the refresh token.
		 */
		var refresh_token_id = null;
		temp_attr = stsuu.getContextAttributes().getAttributeValuesByNameAndType
                             ("refresh_token_id", "urn:ibm:names:ITFIM:oauth:response:metadata");
		if (temp_attr != null && temp_attr.length > 0) {
			refresh_token_id = temp_attr[0];
		}
		/*
		 * Extract the access token.
		 */
		var access_token_id = null;
		temp_attr = stsuu.getContextAttributes().getAttributeValuesByNameAndType
                              ("access_token_id", "urn:ibm:names:ITFIM:oauth:response:metadata");
		if (temp_attr != null && temp_attr.length > 0) {
			access_token_id = temp_attr[0];
		} 

		/*
		 * Extract the access token timeout.
		 */
		var expires_in = null;
		temp_attr = stsuu.getContextAttributes().getAttributeValuesByNameAndType
                              ("expires_in", "urn:ibm:names:ITFIM:oauth:response:attribute");
		if (temp_attr != null && temp_attr.length > 0) {
			expires_in = temp_attr[0];
		}
		
		//Handy for debugging these attributes output the whole STSUU to the log:
		//IDMappingExtUtils.traceString("Current STSUU: " + stsuu.toString());
		
		//Extend Refresh Token Lifetime
		//Use values from definition for consistency but not vital
		var new_refreshlifetime = 3700;
		var min_accesslifetime = 3699;
		if (refresh_token_id != null) {
			//If using Hashed tokens you need to get the internal representation ID:
			//You can remove this if not using hashing.
			var token = OAuthMappingExtUtils.getToken(refresh_token_id);
			refresh_token_id = token.getId();
			var worked = OAuthMappingExtUtils.updateToken(refresh_token_id, new_refreshlifetime, null, null);
			if(!worked) {
			    IDMappingExtUtils.traceString("RT for grant ["+state_id+"] NOT updated.");
			}else 
			{
			    IDMappingExtUtils.traceString("RT for grant ["+state_id+"] was updated ");
			}
		}
		
		//If necessary extend access token lifetime. 
		//Using skew interval of 5 to prevent excessive updates
		if (expires_in < (min_accesslifetime - 5))
		{
			IDMappingExtUtils.traceString("AT for grant [" + state_id + "] should be updated");
			
			//If using Hashed tokens you need to get the internal representation ID:
			//You can remove this if not using hashing.
			var token = OAuthMappingExtUtils.getToken(access_token_id);
			access_token_id = token.getId();
			
			if (access_token_id != null) {
				if(min_accesslifetime != 0) {
					/*
					 * Update the token lifetime. Pass null for date_last_used and enabled, to not update
					 * their value.
					 */
					var is_updated = OAuthMappingExtUtils.updateToken(access_token_id, min_accesslifetime, null, null);
					if(is_updated) {
						/*
						 * Update the expires_in field of the token response.
						 */
						IDMappingExtUtils.traceString("AT for grant [" + state_id + "] was updated.");
						stsuu.addContextAttribute(new 
                                                   com.tivoli.am.fim.trustserver.sts.uuser.Attribute
                                                   ("expires_in" ,"urn:ibm:names:ITFIM:oauth:response:attribute", min_accesslifetime));
					} else {
						IDMappingExtUtils.traceString("AT for grant [" + state_id + "] NOT updated.");
					}
				}
			}
		
		}
		
		
	}
}

This should do the trick.

Comments are closed.

Website Built with WordPress.com.

Up ↑

%d bloggers like this: