restxamarinservicestackrestful-authenticationservicestack-auth

ServiceStack Authenticates both iOS Apps when one is logged in


I'm using the awesome ServiceStack to implement my REST backend which serves two iPhone apps written in Xamarin. Everything works great but i'm struggling in getting sessions to work correctly when the two apps are installed on the same device !

The issue is that if I login in one of the apps the second app gets authenticated and doesn't require me to login as a result of 'isCurrentUserAuthenticated()' method below.

I pass cookies with my requests to mimic the browser and to make sure user doesn't have to pass his credentials every time but I guess the problem is that maybe ServiceStack sees two authentication requests from the same IP so it authenticated them both using the first authentication requests succeeds.

Note : The two apps accesses the same database and UserAuth table but every app supports a user role different than the other.

The only way to fix it is to logout from the second app so the user can login again with his credentials to make everything work.

Can you please help with this ?

Here is the code so far :

public static class BLL
{
    public static JsonServiceClient ServiceClient { get; set; }

    public static string HostUri = "http://test.elasticbeanstalk.com";
    public static string HostDomain = "test.elasticbeanstalk.com";

    static BLL ()
    {
        string ss_id = ConfigRepository.GetConfigString ("ss-id");
        string ss_pid = ConfigRepository.GetConfigString ("ss-pid");

        ServiceClient = new  JsonServiceClient (HostUri);

        ServiceClient.CookieContainer.Add (new Cookie ("ss-id", ss_id, "/", HostDomain));
        ServiceClient.CookieContainer.Add (new Cookie ("ss-pid", ss_pid, "/", HostDomain));
    }


    public static async Task<bool> isCurrentUserAuthenticated ()
    {
        bool result = false;

        try {

            Authenticate authRequest = new Authenticate ();

            // Restore the cookie
            var response = await ServiceClient.PostAsync<AuthenticateResponse> (authRequest);

            NSUserDefaults.StandardUserDefaults.SetString (response.UserId, "UserId");
            NSUserDefaults.StandardUserDefaults.Synchronize ();

            result = true;

        } catch (Exception Ex) {
            result = false;
        }

        return result;
    }

    public static async Task<AuthenticateResponse> Login (string userName, string password)
    {
        Authenticate authRequest = new Authenticate () {
            provider = "credentials",
            UserName = userName,
            Password = password,
            RememberMe = true,
        };

        var response = await ServiceClient.PostAsync<AuthenticateResponse> (authRequest);

        var cookies = ServiceClient.CookieContainer.GetCookies (new Uri (HostUri));

        if (cookies != null) {
            var ss_id = cookies ["ss-id"].Value;
            var ss_pid = cookies ["ss-pid"].Value;

            if (!ss_id.IsNullOrEmpty ()) {
                int r = ConfigRepository.AddConfigKey ("ss-id", ss_id);
                System.Diagnostics.Debug.WriteLine ("ss-id " + ss_id.ToString ());
            }
            if (!ss_pid.IsNullOrEmpty ()) {
                int r = ConfigRepository.AddConfigKey ("ss-pid", ss_pid);
                System.Diagnostics.Debug.WriteLine ("ss-pid " + ss_pid.ToString ());
            }
        }

        NSUserDefaults.StandardUserDefaults.SetString (response.UserId, "UserId");
        NSUserDefaults.StandardUserDefaults.Synchronize ();


        return response;
    }

    public static async Task<AuthenticateResponse> Logout ()
    {
        Authenticate authRequest = new Authenticate () {
            provider = "logout"
        };

        var response = await ServiceClient.PostAsync<AuthenticateResponse> (authRequest);
        return response;
    }
}

Solution

  • The issue is because you're using the same Session Cookies with a shared ServiceClient instance which ends up referencing the same Authenticated Users Session.

    ServiceStack Sessions are only based on the session identifiers (ss-id/ss-pid) specified by the clients cookies, if you use the same cookies you will be referencing the same Authenticated Users Session, they're not affected by IP Address or anything else.

    If you want to authenticate as another user, use a new instance of the ServiceClient (so it's not using an existing Sessions Cookies).