Forum Discussion

SiKing's avatar
SiKing
Community Expert
2 years ago

Problems with refresh OAuth2 token

For our service we are using OAuth2 for authorization.

I have defined an OAuth2 profile in the Auth Manager.

When I click the Get Access Token button manually everything works as expected: a new token is fetched and all my tests pass.

When the token expires I am expecting ReadyAPI to automatically fetch a new token. However, this does not happen. What am I doing wrong?

  • I seem to remember I had already dealt with this sometime in the past. Oh right: 5 years ago! It's a shame this shortcoming still exists in ReadyAPI. 😞

     

    Yki Here is a slightly improved(?) version on that script:

     

    // Name: 'Forced token update'
    // Event: 'SubmitListener.beforeSubmit'
    // Target: '${=submit.request.authType.asBoolean()}' filters only test steps that have Authorization as an option
    
    // https://support.smartbear.com/readyapi/docs/requests/auth/types/oauth2/automate/index.html#on-request
    import com.eviware.soapui.impl.rest.actions.oauth.OltuOAuth2ClientFacade
    import com.eviware.soapui.support.editor.inspectors.auth.TokenType
    import com.eviware.soapui.model.support.ModelSupport
    import com.eviware.soapui.config.AccessTokenStatusConfig
    
    def project = ModelSupport.getModelItemProject(context.getModelItem())
    
    def authProfile = project.authRepository.getEntry("!YOUR AUTH PROFILE NAME!")
    
    if(authProfile.accessTokenStatus != AccessTokenStatusConfig.RETRIEVED_FROM_SERVER) {
    	
    	def oAuthFacade = new OltuOAuth2ClientFacade(TokenType.ACCESS)
    	
    	oAuthFacade.requestAccessToken(authProfile, true, true)
    	
    	// Access token retrieval may take time.
    	def stopLoop = 0	// loop counter to prevent infinite loops in case of problems
    	while(authProfile.accessTokenStatus != AccessTokenStatusConfig.RETRIEVED_FROM_SERVER && stopLoop++ < 6)
    		sleep(5)
    	
    	log.info("Set new token: ${authProfile.accessToken}")
    }

     

  • Yki's avatar
    Yki
    Contributor

    my ex-colleague  wrote following script as a Event : SubmitListenerBeforeSubmit:

     

     

     

    It is not working completely as it should (it requests a new token with every request, but so far I had no problems with it)

     

    // Import the required classes
    import com.eviware.soapui.impl.rest.actions.oauth.OltuOAuth2ClientFacade
    import com.eviware.soapui.support.editor.inspectors.auth.TokenType
    import com.eviware.soapui.model.support.ModelSupport
    
    def authProfileName = "INT_Profile_Name"
    
    if(!submit.getRequest().getAuthType().asBoolean()){
        return // stop if the auth type is null, for example jdbc requests
    }else if(submit.getRequest().getActiveAuthProfile() == null){
        return // stop if the auth profile is null
    }else if(authProfileName == submit.getRequest().getActiveAuthProfile().getName()){
    
        // Set up variables
        def project = ModelSupport.getModelItemProject(context.getModelItem())
        def authProfile = project.getAuthRepository().getEntry(authProfileName)
        def oldToken = authProfile.getAccessToken()
        def tokenType = TokenType.ACCESS
    
        // Create a facade object
        def oAuthFacade = new OltuOAuth2ClientFacade(tokenType)
    
        // Request an access token in headless mode
        oAuthFacade.requestAccessToken(authProfile, true, true)
    
        // Wait until the access token gets updated
        //while(oldToken == authProfile.getAccessToken()) {}
    
        //The sleep method can be used instead of a while loop
        //sleep(3000)
    
        for(int i = 0; i<=3000; i++){
            if(oldToken != authProfile.getAccessToken()){
                break
            }
            sleep(1)
        }
    
        // Post the info to the log
        log.info("Set new token: " + authProfile.getAccessToken())
    }

     

  • SiKing's avatar
    SiKing
    Community Expert

    I seem to remember I had already dealt with this sometime in the past. Oh right: 5 years ago! It's a shame this shortcoming still exists in ReadyAPI. 😞

     

    Yki Here is a slightly improved(?) version on that script:

     

    // Name: 'Forced token update'
    // Event: 'SubmitListener.beforeSubmit'
    // Target: '${=submit.request.authType.asBoolean()}' filters only test steps that have Authorization as an option
    
    // https://support.smartbear.com/readyapi/docs/requests/auth/types/oauth2/automate/index.html#on-request
    import com.eviware.soapui.impl.rest.actions.oauth.OltuOAuth2ClientFacade
    import com.eviware.soapui.support.editor.inspectors.auth.TokenType
    import com.eviware.soapui.model.support.ModelSupport
    import com.eviware.soapui.config.AccessTokenStatusConfig
    
    def project = ModelSupport.getModelItemProject(context.getModelItem())
    
    def authProfile = project.authRepository.getEntry("!YOUR AUTH PROFILE NAME!")
    
    if(authProfile.accessTokenStatus != AccessTokenStatusConfig.RETRIEVED_FROM_SERVER) {
    	
    	def oAuthFacade = new OltuOAuth2ClientFacade(TokenType.ACCESS)
    	
    	oAuthFacade.requestAccessToken(authProfile, true, true)
    	
    	// Access token retrieval may take time.
    	def stopLoop = 0	// loop counter to prevent infinite loops in case of problems
    	while(authProfile.accessTokenStatus != AccessTokenStatusConfig.RETRIEVED_FROM_SERVER && stopLoop++ < 6)
    		sleep(5)
    	
    	log.info("Set new token: ${authProfile.accessToken}")
    }

     

  • smcclay's avatar
    smcclay
    Occasional Contributor

    This is a slightly updated version of the script that can be put into the Automation for the auth profile and will only renew when expired:

     

     

    // Import the required classes
    import com.eviware.soapui.impl.rest.actions.oauth.OltuOAuth2ClientFacade;
    import com.eviware.soapui.support.editor.inspectors.auth.TokenType;
    import com.eviware.soapui.model.support.ModelSupport;
    
    // Set up variables
    def project = ModelSupport.getModelItemProject(context.getModelItem());
    def stepProfile = context.getCurrentStep().getHttpRequest().getSelectedAuthProfile()
    def authProfile = project.getAuthRepository().getEntry(stepProfile);
    def oldToken = authProfile.getAccessToken();
    def tokenType = TokenType.ACCESS;
    
    // Create a facade object
    def oAuthFacade = new OltuOAuth2ClientFacade(tokenType);
    
    // Request an access token in headless mode
    oAuthFacade.requestAccessToken(authProfile, true, true);
    
    // Wait until the access token gets updated
    for(int i = 0; i<=3000; i++){
    	if(oldToken != authProfile.getAccessToken()){
    		break
    	}
    	sleep(1)
    }

     

    I would suggest this is a work-around for a ReadyAPI bug as we should be able to set this type of token to renew automatically.

     

    Regards,

    --

    Stephen

  • nmrao's avatar
    nmrao
    Champion Level 3

    Does the authentication server provides refresh token when you get the token? If not, then ReadyAPI may not automatically refresh it when the token expires.

     

    Was it working earlier and started facing this now? what changes?

    • SiKing's avatar
      SiKing
      Community Expert

      I am using Client ID + Client Secret. I _believe_ that generates a refresh token, but am not certain. How would I check?

    • SiKing's avatar
      SiKing
      Community Expert

      I just got the token manually by constructing a REST request. There is no refresh_token. 😞

      This is from MS Azure. Is no refresh_token normal?

      How would I setup the automation to "just get a new one". Since I am using Client ID + Client Secret there is no login screen; I just need to get a new token.

  • nmrao's avatar
    nmrao
    Champion Level 3

    There must be separate API to get the token where you can see the response payload and see what data does it contain.

    Or you can check the swagger page which also allows to get the token or authenticate.

     

    What is the token expiratation time? (to know how frequently token to be generated)

    • sharon19_in's avatar
      sharon19_in
      New Member

      Im using the free version, since there is no auth manager what options do we have to manage the auto refresh  ?

  • aviktory's avatar
    aviktory
    New Contributor

    Hi,

    I had same issue with my REST API testing, but found an easy solution , without any additional script. Basically, a "javascript" part has to be added to the project file(xml ). It can be simply added by some dummy steps(pic1), adding 3rd page in automation, click run, and then you can delete the 3rd page(pic2). I left  all pages blank. On pic3, you can see the part of code added to the xml project file, with these steps. Refresh of token then works automatically anytime after it expires, when you execute API request. I use the free SoapUI version.