Question

I want to make my WinForms-App to use the SingleSign-On (SSO) feature with Microsoft Accounts.
I created a LiveApp and I'm able to Login to my App with the LiveSDK 5.4.
But everytime I click on my Login-Button the permissions list appears and I need to accept it again.

This is my code:

private const string ClientID = "{MY_CLIENT_ID}";
private LiveAuthClient liveAuthClient;
private LiveConnectClient liveConnectClient;
string[] scopes = new string[] { "wl.offline_access", "wl.emails", "wl.signin" };

private void buttonLogin_Click(object sender, EventArgs e)
{
    liveAuthClient = new LiveAuthClient(ClientID);
    webBrowser1.Navigate(liveAuthClient.GetLoginUrl(scopes));
}

private async void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
{
    if (this.webBrowser1.Url.AbsoluteUri.StartsWith("https://login.live.com/oauth20_desktop.srf"))
    {
        AuthResult authResult = new AuthResult(this.webBrowser1.Url);
        if (authResult.AuthorizeCode != null)
        {
            try
            {
                LiveConnectSession session = await liveAuthClient.ExchangeAuthCodeAsync(authResult.AuthorizeCode);
                this.liveConnectClient = new LiveConnectClient(session);
                LiveOperationResult meRs = await this.liveConnectClient.GetAsync("me");
                dynamic meData = meRs.Result;
                if(string.Equals(meData.emails.account, MyAppUser.EmailAddress))
                    MessageBox.Show("Successful login: " + meData.name);
            }
            catch (LiveAuthException aex)
            {
                MessageBox.Show("Failed to retrieve access token. Error: " + aex.Message);
            }
            catch (LiveConnectException cex)
            {
                MessageBox.Show("Failed to retrieve the user's data. Error: " + cex.Message);
            }
        }
        else
        {
            MessageBox.Show(string.Format("Error received. Error: {0} Detail: {1}", authResult.ErrorCode, authResult.ErrorDescription));
        }
    }
}

What I need to change? I don't want the User to accept the permissions on each login.

Was it helpful?

Solution

You can use IRefreshTokenHandler to save token as following example:

public class RefreshTokenHandler : IRefreshTokenHandler
{
    private string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\oneDrive\\RefreshTokenHandler\\RefreshTokenInfo.RefreshToken-me";
    public Task<RefreshTokenInfo> RetrieveRefreshTokenAsync()
    {
        return Task.Factory.StartNew<RefreshTokenInfo>(() =>
        {
            if (File.Exists(path))
            {
                return new RefreshTokenInfo(File.ReadAllText(path));
            }
            return null;
        });
    }

    public Task SaveRefreshTokenAsync(RefreshTokenInfo tokenInfo)
    {
        // Note: 
        // 1) In order to receive refresh token, wl.offline_access scope is needed.
        // 2) Alternatively, we can persist the refresh token.
        return Task.Factory.StartNew(() =>
        {
            if (File.Exists(path)) File.Delete(path);
            if (!Directory.Exists(Path.GetDirectoryName(path))) Directory.CreateDirectory(Path.GetDirectoryName(path));
            File.AppendAllText(path, tokenInfo.RefreshToken);
        });
    }
}

after that you get session as following:

RefreshTokenHandler handler = new RefreshTokenHandler();
liveAuthClient = new LiveAuthClient(ClientID, handler);
var Session = liveAuthClient.InitializeAsync(scopes).Result.Session;
if (Session == null)
{
    webBrowser1.Navigate(liveAuthClient.GetLoginUrl(scopes));
}
else
{
    try
    {
        this.liveConnectClient = new LiveConnectClient(Session);
        LiveOperationResult meRs = await this.liveConnectClient.GetAsync("me");
        dynamic meData = meRs.Result;
        if (string.Equals(meData.emails.account, MyAppUser.EmailAddress))
            MessageBox.Show("Successful login: " + meData.name);
    }
    catch (LiveAuthException aex)
    {
        MessageBox.Show("Failed to retrieve access token. Error: " + aex.Message);
    }
    catch (LiveConnectException cex)
    {
        MessageBox.Show("Failed to retrieve the user's data. Error: " + cex.Message);
    }
}

OTHER TIPS

I've only used this API in Objective C, but I had to follow two steps.

  1. Use the wl.offline_access scope. (Which you're already doing)
  2. You only show the login screen if the sessions object is null. If your session object is already populated, you can proceed as you would if the sign in was successful.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top