registering callback function for OAuth

Hello there,

I've made an app that uses OAuth to retrieve user data, so I've used registerForOAuthMessages to define a callback function. In the codes hereafter (where the URLs have been obfuscated) I trigger the function "go" when a background event is fired, this function "go" makes the OAuth window pop-up 

using Toybox.Communications as Comm;
using Toybox.System as Sys;
using Toybox.WatchUi as Ui;
using Toybox.Application as App;
using Toybox.Time.Gregorian as Calendar;

const ClientId = "...";
const ClientSecret = "...";
const ApiUrl = "...";
const RedirectUri = "https://localhost/";   

// The LoginTransaction is a special transaction that handles
// getting the OAUTH token.$
(:background)
class LoginTransaction
{
    hidden var _delegate;

    // Constructor
    function initialize(delegate) {
        _delegate = delegate;
        Sys.println("initialize LoginTransaction");
        Comm.registerForOAuthMessages(method(:accessCodeResult));
    }

    // Handle converting the authorization code to the access token
    // @param value Content of JSON response
    function accessCodeResult(value) {
    	Sys.println("accessCodeResult " + value);
        if( value.data != null) {
            Sys.println("accessCodeResult Ok");
        }
        else {
            Sys.println("Error in accessCodeResult");
        }
    }




    // Method to kick off tranaction
    
    function go() {
        // Kick of a request for the user's credentials. This will
        // cause a notification from Connect Mobile to file
        Sys.println("go");
        Comm.makeOAuthRequest(
            // URL for the authorization URL
            "...",//there is a valid URL here but it is private
            // POST parameters
            {},
            // Redirect URL
            $.RedirectUri,
            // Response type
            Comm.OAUTH_RESULT_TYPE_URL,
            // Value to look for
            {"responseCode" => "OAUTH_CODE", "responseError" => "OAUTH_ERROR"}
            );
    }

}

using Toybox.Background as Bg;
using Toybox.System as Sys;

// The Service Delegate is the main entry point for background processes
// our onTemporalEvent() method will get run each time our periodic event
// is triggered by the system.

(:background)
class JsonBackground extends Toybox.System.ServiceDelegate {
	hidden var _transaction=null;
	
	function initialize() {
		Sys.ServiceDelegate.initialize();
		Bg.registerForTemporalEvent(new Time.Duration(5 * 60));
		var ltd=new LoginTransactionDelegate();
	 	_transaction = new LoginTransaction(ltd);

	}
		
    function onTemporalEvent() {
    	System.println("onTemporalEvent2");
        _transaction.go();
        Bg.exit(1);
       
    }
    

}

using Toybox.Background as Bg;
using Toybox.System as Sys;
using Toybox.Communications as Comm;
using Toybox.WatchUi as Ui;

(:background)
class LoginTransactionDelegate extends TransactionDelegate{

    // Constructor
    function initialize() {
        TransactionDelegate.initialize();
    }

    // Handle a error from the server
 	function handleResponse(data) {
       System.println("OK "+data);
    }
    
    function handleError(code) {
        var msg = "err";
        msg += code;
        System.println(msg); 
    }

The OAuth window pop-up correctly when the Background event is triggered, then I enter my credentials correctly and the window close but the "accessCodeResult" function seems not to be called.

Does someone have an idea?
Thanks in advance

  • Now if launch the simulator and trigger background event the pop-up window pops and after successful login, if I do nothing the callback function is not called. But, I don't know why, if I close the simulator and relaunch it the callback function is triggered !?!?

  • Ok more info
    here is my App class:

    using Toybox.Application as App;
    using Toybox.Background;
    using Toybox.System as Sys;
    using Toybox.WatchUi as Ui;
    using Toybox.Time;
    using Toybox.UserProfile;
    using Toybox.PersistedContent;
    using Toybox.System;
    using Toybox.Communications as Comm;
    
    (:background)
    class KronosApp extends App.AppBase {
    	var inBackground=false;
    	var bg=null;
        
        function initialize() {
            AppBase.initialize();
    
        	if(Toybox.System has :ServiceDelegate) {
        		Background.registerForTemporalEvent(new Time.Duration(5 * 60));
        	} else {
        		Sys.println("****background not available on this device****");
       		}
       		
          }
    
        // onStart() is called on application start up
        function onStart(state) { 
        	
        }
    
        // onStop() is called when your application is exiting
        function onStop(state) {
        	if(!inBackground) {
        		Background.deleteTemporalEvent();
        		System.println("stop");
        	}
        	
        }
        
        function onAppInstall(){
    	    System.println("onAppInstall");
        }
        
        function onAppUpdate(){
    	    System.println("onAppUpdate");
        }
    
    
        //! Return the initial view of your application here
        function getInitialView() {
        	System.println("getInitialView");
        	var Kview = new KronosView();
            return [ Kview];
        }
        
        //store json data in bgdata
        function onBackgroundData(data) {
    		System.println("onbg "+ data);
        }    
    
        function getServiceDelegate(){
        	inBackground=true;	
        	System.println("getServiceDelegate");
            return [new JsonBackground()];
        }
    
    
    }

    And the JsonBackground class

    using Toybox.Background as Bg;
    using Toybox.System as Sys;
    using Toybox.Time as Tm;
    
    // The Service Delegate is the main entry point for background processes
    // our onTemporalEvent() method will get run each time our periodic event
    // is triggered by the system.
    
    (:background)
    class JsonBackground extends Toybox.System.ServiceDelegate {
    	hidden var _transaction=null;
    	
    	function initialize() {
    		Sys.ServiceDelegate.initialize();
    	 	_transaction = new LoginTransaction();
    
    	}
    		
        function onTemporalEvent() {
        	System.println("onTemporalEvent2");
            _transaction.go();
            Bg.exit(1);
           
        }
    
    
    }

    The strange thing is the fact I've got this in the console when I launch the app in the  simulator:

    Background: getServiceDelegate
    Background: initialize LoginTransaction
    Background: onAppInstall
    getInitialView

    and if I trigger the background event it adds those line:
    Background: getServiceDelegate
    Background: initialize LoginTransaction
    Background: onTemporalEvent2
    Background: go
    onbg 1

    The second part is normal but I don't know why I've got Background event (getServiceDelegate) at app launch

  • Actually, the first part is normal too.  You're seeing that getSeviceDelegate is related to onAppInstall/onAppUpdate, which runs in the background.

  • Thanks, Jim, if I comment those 2 functions I've got this now:

    1. the Oauth window pops up immediately (good point)

    2. I have this in the console (still two  initialize LoginTransaction)

        Background: getServiceDelegate
        Background: initialize LoginTransaction
        Background: getServiceDelegate
        Background: initialize LoginTransaction
        Background: onTemporalEvent2
        Background: go
        getInitialView
        onbg 1

    3.The callback function is still not called even after succesful login (maybe the registerForOAuthMessages is not at a right place)

  • That's still because of onAppInstall/onAppUpdate because you're doing the call in initialize in the service delegate.

    The process still occurs even if you don't override them in your own appBase.

  • Ok, so if I understand it is normal so it is not related to the fact that the callback function is not called

  • I'm curious, is there someone who had successfully implemented an OAuth here?

  • I guess I'm really not sure why you are trying to do this from a background process. The user should probably be walked through this initial OAuth authorization phase as part of the application setup on first launch. I've gotten OAuth to work from outside the background process runs and I don't know that this is really what background processing was intended for. Once you've done an initial OAuth setup you'll have the parts to execute background makeWebRequests using the authorization. This is particularly difficult for people to troubleshoot since they don't have the endpoint to really walk through it and test.

  • Thanks lcj2 for your reply,
    I do OAuth in the background because I develop a data field app.


    We use OAuth for checking a user personalized JSON with some data to have an app which help the cyclist to improve his training so we need to fetch a JSON before his session

    So you think we should check the credential at app install/update (onAppUpdate ?) and store the id? (how?)