.Net Core 2.1 - OAuth 2

Anyone have any article recommendations for setting up OAuth with a .Net Core 2.1 web application?

I’ve never utilized OAuth and it doesn’t appear very well documented for a non-built in provider.

Thanks for any help or pointers you may have.

Mark

10replies Oldest first
  • Oldest first
  • Newest first
  • Active threads
  • Popular
  • Hey, Mark Leistner . I'm not very well versed in the .Net world, but this looked as if it could be useful: https://www.jerriepelser.com/blog/authenticate-oauth-aspnet-core-2/ Good luck and post more questions if you get stuck.

    Reply Like
    • George I've got the easier version working, have yet to figure out the Authorization Code Grant workflow yet though.  Oh well, baby steps...

      Thanks for the link, between that and some code I found on github I was able to get it at least functional.

      I do have a follow up questions though, is there a way to deauthorize, or logout of the service from the api?

      Reply Like
    • Mark , glad to hear you're making progress!

      Mark Leistner said:
      is there a way to deauthorize, or logout of the service from the api

       Your user isn't really logged in to our API. You used the YNAB web app to verify the authenticity of your user. Once the YNAB web app verifies her authenticity, we no longer need the web app; your app can talk to the YNAB API on behalf of your now authenticated user.

      If a user wants to rescind that authorization, she needs to log in to the YNAB web app, go to Developer Settings, and manage their connections.

      (The accepted answer to this SO post may also help.)

      Let me know if I'm missing something or if you need more. Good luck!

      Reply Like
    • alexdresko
    • I'm not a player, I just code a lot.
    • Forest_Green_Sidewinder
    • 3 mths ago
    • Reported - view

    For the record, here's my ConfigureServices. Don't know if it's correct, but it seems to work. 

     

            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.Configure<CookiePolicyOptions>(options =>
                {
              // This lambda determines whether user consent for non-essential cookies is needed for a given request.
              options.CheckConsentNeeded = context => true;
                    options.MinimumSameSitePolicy = SameSiteMode.None;
                });
    
                services.AddHttpClient();
    
                // https://www.jerriepelser.com/blog/authenticate-oauth-aspnet-core-2
                services.AddAuthentication(options =>
                  {
                      options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                      options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                      options.DefaultChallengeScheme = "ynab";
                      options.DefaultSignOutScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                  })
                  .AddCookie()
                  .AddOAuth("ynab", options =>
                  {
                      options.ClientId = Configuration["ynablint:ynab:ClientId"];
                      options.ClientSecret = Configuration["ynablint:ynab:ClientSecret"];
                      options.CallbackPath = new PathString("/signin-ynab");
                      options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    
                      options.AuthorizationEndpoint = "https://app.youneedabudget.com/oauth/authorize";
                      options.TokenEndpoint = "https://app.youneedabudget.com/oauth/token";
                      options.SaveTokens = true;
    
                      options.Events.OnCreatingTicket = context =>
                      {
                          context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, context.AccessToken, ClaimValueTypes.String, context.Options.ClaimsIssuer));
                          context.Identity.AddClaim(new Claim(ClaimTypes.Name, context.AccessToken, ClaimValueTypes.String, context.Options.ClaimsIssuer));
    
                          if (context.Properties.GetTokens() is List<AuthenticationToken> tokens)
                          {
                              tokens.Add(new AuthenticationToken()
                              {
                                  Name = "ynab_access_token",
                                  Value = context.AccessToken
                              });
                              context.Properties.StoreTokens(tokens);
                          }
    
                          return Task.CompletedTask;
                      };
    
                      options.Events.OnTicketReceived = context =>
                      {
                          return Task.CompletedTask;
                      };
                  });
    
                services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    
                services.AddSignalR();
            }
    
    Reply Like
    • alexdresko Thank you.  I ended up with somewhat similar code.  Seems to be working so far, and I have functional start to my website.

      I still have some stuff to add and a few UI things left to do, but I’ve at least got it published and working.  First time I’ve ever used AWS serverless... it’s been interesting.  But a good learning project.

      Reply Like 1
  • Just to share along with everyone else, here is my copy of ConfigureServices:

            public void ConfigureServices(IServiceCollection services)
            {
                services.Configure<CookiePolicyOptions>(options =>
                {
                    options.CheckConsentNeeded = context => true;
                    options.MinimumSameSitePolicy = SameSiteMode.None;
                });

                services.AddAuthentication(options =>
                {
                    options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                })
                .AddCookie(options =>
                {
                    options.Cookie.Expiration = new TimeSpan(2, 0, 0);
                    options.ExpireTimeSpan = new TimeSpan(2, 0, 0);
                })
                .AddOAuth("ynab", options =>
                {
                    options.ClientId = Configuration["ynab:ClientId"];
                    options.ClientSecret = Configuration["ynab:ClientSecret"];
                    options.CallbackPath = new PathString("/signin-ynab");
                    options.AuthorizationEndpoint = $"https://{Configuration["ynab:Domain"]}/oauth/authorize";
                    options.TokenEndpoint = $"https://{Configuration["ynab:Domain"]}/oauth/token";
                    options.UserInformationEndpoint = $"https://{Configuration["ynab:userinfo"]}/v1/user";
                    options.SaveTokens = true;
                    options.Scope.Clear();
                    options.Events = new OAuthEvents
                    {
                        OnCreatingTicket = async context =>
                        {
                            var api = new YnabApi(context.AccessToken);
                            var user = api.GetUser();

                            context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Data.User.UserId, ClaimValueTypes.String, context.Options.ClaimsIssuer));
                        },
                        OnTicketReceived = context =>
                        {
                            context.Properties.IsPersistent = true;
                            context.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddHours(2);
                            return Task.FromResult(0);
                        }
                    };
                });

                services.AddMvc().AddRazorPagesOptions(options =>
                {
                    options.Conventions.AddAreaPageRoute("Identity", "/Login", "");
                }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

                services.AddDefaultAWSOptions(Configuration.GetAWSOptions());
                services.AddAWSService<IAmazonS3>();
            }

    Reply Like
    • alexdresko
    • I'm not a player, I just code a lot.
    • Forest_Green_Sidewinder
    • 2 mths ago
    • Reported - view

    Okay, I'll admit to being dumb about this kind of stuff. 

    Do we need to do anything special to support "refresh tokens"? I don't know how that's supposed to work. 

    Reply Like
    • alexdresko I have no idea.  I was initially planning on working towards that, but I really haven't seen the need to do so, since I am making a web application and don't want to deal with user accounts and all of that. 

      For my case, I'd just prefer to have the user authenticate using YNAB and if the token times out, they need to authenticate again.  

      Reply Like
  • Mark Leistner , _Will_ just posted his YNAB starter kit in .Net Core 2.2 project. It might be of use to you. Cheers.

    Reply Like
    • George Thanks for the heads up, I’ll take a look at that.

      i currently have my application up, running and deployed.  So it’s at least authorizing correctly.  Yay!

      Reply Like 1
Like Follow
  • 2 mths agoLast active
  • 10Replies
  • 158Views
  • 3 Following