GithubHelp home page GithubHelp logo

Comments (30)

ginach avatar ginach commented on July 29, 2024

You have a couple options:

  1. Use the default auth flow. This requires implementing IWebAuthenticationUi for displaying the authentication UI to the user and passing that into the client. It looks like an extension method is missing, I'll make a note to fix that, but you can do this:

    var client = OneDriveClient.GetMicrosoftAccountClient(
    appId,
    returnUrl,
    scopes,
    clientSecret,
    serviceInfoProvider: new ServiceInfoProvider(webAuthenticationUi));

  2. Create your own authentication provider implementation that wraps MicrosoftAccountAuthenticationExtensions::UseMicrosoftAccountAuthentication. To do that, you can either implement your own IAuthenticationProvider or inherit from AuthenticationProvider. Inheriting from AuthenticationProvider allows you to use the credential caching system we have in the SDK. Here is an example of one of our implemented authentication providers. You can then create the client like this:

    var client = OneDriveClient.GetMicrosoftAccountClient(
    appId,
    returnUrl,
    scopes,
    clientSecret,
    serviceInfoProvider: new ServiceInfoProvider(authenticationProvider));

After creating the client you call await client.AuthenticateAsync() and you'll be good to make requests with it.

from onedrive-sdk-csharp.

opcodewriter avatar opcodewriter commented on July 29, 2024

Please correct me if I'm wrong, I don't see how it would be possible to use IWebAuthenticationUi in an
ASP.NET MVC app.
On server, when calling AuthenticateAsync(), this is going to call IWebAuthenticationUi implementation. But since showing the login UI is on client side, there's no way to communicate the results to the IWebAuthenticationUi instance, the instance is gone.

from onedrive-sdk-csharp.

ginach avatar ginach commented on July 29, 2024

The feasibility of option 1 differs depending on the app. It sounds like it's not an option for yours so you'll probably want to look into option 2.

from onedrive-sdk-csharp.

opcodewriter avatar opcodewriter commented on July 29, 2024

Can the access token returned by authenticating with Microsoft account be used to call OneDrive API?
I don't understand how the Microsoft signin and OneDrive sigin work together..

I'm still lost...
I spent time looking at AuthenticationProvider, MicrosoftAccountAuthenticationProvider implementation and other classes.
I understand the idea, but I just don't know how to use all together, what I need to implement..
Is there any sample which does it for an ASP.NET app?

from onedrive-sdk-csharp.

ginach avatar ginach commented on July 29, 2024

We don't have a sample currently but are working on putting one together. I'll respond when we have something.

from onedrive-sdk-csharp.

mybluedog avatar mybluedog commented on July 29, 2024

I think I have a similar problem. I get an offline refresh_token in one system using REST. Then I have a C# client on another system that needs to authenticate using just the refresh_token and the client_id (and redirect_uri and scope, and whatever else OAuth demands). Can this be done?

from onedrive-sdk-csharp.

ginach avatar ginach commented on July 29, 2024

Yes, it can. There's a bug (IAuthenticationProvider doesn't have the CurrentAccountSession setter anymore) that I'll be putting a fix out for tomorrow, but after the fix you can do the following for an authenticated client in the above scenario:

var client = OneDriveClient.GetMicrosoftAccountClient(
    client_id,
    redirect_uri,
    scopes);

client.AuthenticationProvider.CurrentAccountSession = new AccountSession
{
    RefreshToken = "token"
};

await this.oneDriveClient.AuthenticateAsync();

I understand the calling pattern here is a little bit awkward, but it'll accomplish what you want.

The reason why this works is the authentication provider goes through the following flow:
1. Is there a current account session that isn't expiring? If so, return it.
2. If not, do we have a refresh token? If so, use it to get a new auth token using the information the client has about the app.
3. If the above didn't work and we have an IWebAuthenticationUi implementation use it to authenticate the user via the UI flow.
4. If all of the above didn't work, return null.

from onedrive-sdk-csharp.

mybluedog avatar mybluedog commented on July 29, 2024

Sounds good. We'll try it when it's ready.

from onedrive-sdk-csharp.

ginach avatar ginach commented on July 29, 2024

@mybluedog The new package is now up, v 1.1.9.

from onedrive-sdk-csharp.

mybluedog avatar mybluedog commented on July 29, 2024

Thanks for your help with this.

Unfortunately, in the code above, client.AuthenticationProvider is null and there's no setter for it, so the AccountSession can't be set. I decided to implement my own AuthenticationProvider like this...

using OD = Microsoft.OneDrive.Sdk;

namespace
{
    class AuthenticationProvider : OD.IAuthenticationProvider
    {
        OD.AccountSession m_session;

        public AuthenticationProvider(string refreshToken)
        {
            m_session = new OD.AccountSession()
            {
                RefreshToken = refreshToken,
                ExpiresOnUtc = DateTime.SpecifyKind(DateTime.MaxValue, DateTimeKind.Utc),
                ClientId = "{clientId}",
                Scopes = new[] { "wl.signin", "wl.offline_access", "onedrive.readonly" },
                AccountType = OD.AccountType.MicrosoftAccount
            };
        }

        public OD.AccountSession CurrentAccountSession
        {
            get
            {
                return m_session;
            }

            set
            {
                throw new NotImplementedException();
            }
        }

        public Task AppendAuthHeaderAsync(HttpRequestMessage request)
        {
            request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(OD.Constants.Headers.Bearer, m_session.AccessToken);
            return Task.WhenAll(); // == Task.CompletedTask
        }

        public Task<OD.AccountSession> AuthenticateAsync()
        {
            return Task<OD.AccountSession>.FromResult(m_session);
        }

        public Task SignOutAsync()
        {
            throw new NotImplementedException();
        }
    }
}

And I'm creating my client like this...

OD.IOneDriveClient oneDriveClient = OD.OneDriveClient.GetMicrosoftAccountClient(
    clientId,
    "https://login.live.com/oauth20_desktop.srf", // For now, I've created the refresh_token using this return URI
    new[] { "wl.signin", "wl.offline_access", "onedrive.readonly" },
    clientSecret,
    serviceInfoProvider: new OD.ServiceInfoProvider(
        new AuthenticationProvider(@"{refresh_token}")
        )
    );

OD.AccountSession session = oneDriveClient.AuthenticateAsync().Result;
return (oneDriveClient != null && oneDriveClient.IsAuthenticated) ? oneDriveClient : null; // IsAuthenicatied == true

But the problem is that even though oneDriveClient.IsAuthenticated returns true now, the access_token is null and subsequent calls on the client fail. I suppose that I need to implement functionality to convert the refresh_token to an access_token somewhere, but I'm wondering if there's an easier way to leverage that code that is already present in the SDK?

from onedrive-sdk-csharp.

ginach avatar ginach commented on July 29, 2024

You are correct, I forgot that AuthenticateAsync() does a few more steps. There's a way to do it with existing functionality, but it's not straighforward. PR #31 adds some extensions to do this, please take a look.

With the changes you can do something like this to get an authenticated client using refresh token:

await OneDriveClient.GetSlientlyAuthenticatedMicrosoftAccountClient(
    clientId,
    returnUrl,
    scopes,
    refreshToken)

from onedrive-sdk-csharp.

ginach avatar ginach commented on July 29, 2024

The new package with the refresh token fix is up.

from onedrive-sdk-csharp.

mybluedog avatar mybluedog commented on July 29, 2024

@ginach Working well! Please note typo in GetSlientlyAuthenticatedMicrosoftAccountClient :-)

from onedrive-sdk-csharp.

mybluedog avatar mybluedog commented on July 29, 2024

@ginach Hi Gina

We had this function working when we were using the well-known redirect_uri (https://login.live.com/oauth20_desktop.srf). Since then, we have switched to using a custom redirect_uri (http://localhost/oauth).

Through experimentation (using REST) we learned that we now need to pass in the client_secret. This means we now need to call the function that accepts a client_secret...

public static Task<IOneDriveClient> GetSlientlyAuthenticatedMicrosoftAccountClient(string appId, string returnUrl, string[] scopes, string clientSecret, string refreshToken, IServiceInfoProvider serviceInfoProvider, CredentialCache credentialCache = null, IHttpProvider httpProvider = null);

...but this function also requires an IServiceInfoProvider (and therefore a ServiceInfo object and an IAuthenticationProvider).

I will attempt to implement these tomorrow, but I don't understand why they are required since REST requires just the first four params to work (string appId, string returnUrl, string[] scopes, string clientSecret).

I tried leaving IServiceInfoProvider as null, but that didn't work. Can you offer some guidance on the minimum implementation needed to get this working? (I don't need code, just an indication on what needs to be provided would be great).

from onedrive-sdk-csharp.

ginach avatar ginach commented on July 29, 2024

Yup, this is a bug. I had done a lot of testing with the desktop client flow but missed the client secret flow. I have a fix locally and will have an updated package out probably tomorrow.

from onedrive-sdk-csharp.

mybluedog avatar mybluedog commented on July 29, 2024

@ginach Any update on this?

from onedrive-sdk-csharp.

ginach avatar ginach commented on July 29, 2024

Sorry for the delay, I wound up getting sick. Finishing up testing now and will update the package after that.

from onedrive-sdk-csharp.

mybluedog avatar mybluedog commented on July 29, 2024

Thanks Gina. I hope you're feeling better.

from onedrive-sdk-csharp.

ginach avatar ginach commented on July 29, 2024

@mybluedog The new package (v1.1.20) is now uploaded.

from onedrive-sdk-csharp.

mybluedog avatar mybluedog commented on July 29, 2024

This is working for us with Consumer accounts now.

from onedrive-sdk-csharp.

byhub avatar byhub commented on July 29, 2024

Hi @ginach

I havent been able to get authenticated client..I am trying this for asp.net mvc app..

MicrosoftAccountServiceInfo _serviceinfo = new MicrosoftAccountServiceInfo();
_serviceinfo.AppId = settings.ClientId;
_serviceinfo.ClientSecret = settings.ClientSecret;
_serviceinfo.ReturnUrl = returnURL;
_serviceinfo.Scopes = Scopes;
MicrosoftAccountAuthenticationProvider authenticationProvider = new MicrosoftAccountAuthenticationProvider(_serviceinfo);
_client = OneDriveClient.GetMicrosoftAccountClient(settings.ClientId, returnURL, Scopes, settings.ClientSecret, serviceInfoProvider: new ServiceInfoProvider(authenticationProvider)); 
_session = _client.AuthenticateAsync().Result;

I keep getting failed authentication error.. by the way when I check client object, I see that Authentication provider is null.. am I missing something?

from onedrive-sdk-csharp.

ginach avatar ginach commented on July 29, 2024

@byhub With the way you're initializing the client, whithout an IWebUi instance, it'll hit the silent auth flow but not have a refresh token present to redeem for an access token. This will fail the auth flow.

What you want to do is initialize the client using refresh token. Or create your own IAuthenticationProvider implementation and pass that in to the service info provider. Here's how you can get the client using refresh token:

await OneDriveClient.GetSlientlyAuthenticatedMicrosoftAccountClient(
    clientId,
    returnUrl,
    scopes,
    clientSecret,
    refreshToken);

from onedrive-sdk-csharp.

byhub avatar byhub commented on July 29, 2024

@ginach hmm probably it will be a silly question but isnt it what I am doing already in my code snippet I shared above.. for IAuthenticationProvider implementation, I use MicrosoftAccountAuthenticationProvider class that is IAuthenticationProvider implementation and pass it into serviceinfoprovider within extensin call..

why do I need to create another IAuthenticationProvider implementation..?

from onedrive-sdk-csharp.

skobba avatar skobba commented on July 29, 2024

@byhub you are not the only one struggelig, I'm having a hard time using this with "New Project" -> ASP .NET 5 Web Application Template (using multi-domain). Cheers

from onedrive-sdk-csharp.

ginach avatar ginach commented on July 29, 2024

MSA OAuth requires a user prompt for consent. We have default UI implemented for WinStore apps and an implementation using WinForms to prompt. With ASP.NET web applications this can create an interesting problem as prompting users usually requires switching to a different view context and the default UI implementations aren't sufficient, or the code is running server-side and cannot prompt the user. In these cases, the recommendation is for the app to use either of these flows:

  1. Create a signup page that will have to user do the initial "Connect with OneDrive", making sure to include the wl.offline_access scope so a refresh token will be returned. Then, store those refresh tokens and initialize a client using GetSilentlyAuthenticatedMicrosoftAccountClient(). Note that tokens are valid for a year and a new one will be retrieved anytime an access token is retrieved. So, after authenticating the client you'll want to store the new token.
  2. Handle your own authentication and implement your own IAuthenticationProvider that will append the auth tokens to the request.

I'm currently working on implementing a 3rd option where the app handles its own initial OAuth call using the authorization code grant type and can pass that code to the client initialization. I have it implemented for business auth flows but not yet for consumer.

from onedrive-sdk-csharp.

skobba avatar skobba commented on July 29, 2024

@ginach, is the business implementation in one of your repo branches, businessAuthFixes?

from onedrive-sdk-csharp.

ginach avatar ginach commented on July 29, 2024

Correct. It's also the current PR into Dev.

from onedrive-sdk-csharp.

skobba avatar skobba commented on July 29, 2024

A lot of the auth code is in OneDriveSdk.WindowsForms including the BusinessClientExtensions. Find it difficult to get this running on ASP .NET. I'm trying this with the new ASP .NET Core 1.0 that bootstraps the app with auth middleware in the Startup.cs file. Would it be a good idea to be able to bootstrap the app with OneDriveSDK capabilities? Lots of OneDrive browsers out there like: OneDriveExplorer (Graph/TypeScript) and OneDriveForBusiness-Explorer-MVC. Just trying to make my own OneDriveExplorerASP.NETCore1.0 with your new API. Not sure how to proceed now. By the way, I think you have to update the WinForm sample to include the client_secret. Cheers

from onedrive-sdk-csharp.

ginach avatar ginach commented on July 29, 2024

There are a few approaches you can take. Please feel free to email me at ginach @ microsoft . com to talk about some approaches and so I can get an idea of how I can improve the calling model here.

from onedrive-sdk-csharp.

ginach avatar ginach commented on July 29, 2024

Business auth changes are in the latest package push. For an MVC sample, take a look at our webhooks sample app.

from onedrive-sdk-csharp.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.