137

First I'll sketch my project:

For my internship I need to add functionality to an existing system. A 3rd party client must be able to access data from AX Webservices once he is authorised by the user via OAuth2. I understand that I need to make a 'proxy web service' whereto the client can make its calls and that calls the AX services but I am a bit unsure about the OAuth2 part. Most tutorials and guides are about using ASP.NET's Identity for Facebook or Google-logins. I do not need that, I need to use existing credentials so I need to make my own OAuth2 service.

I find it hard to find tutorials, guides or explanations on this. I understand OAuth2 and what needs to be done, but I have never done such a thing before and find it hard to start. The closest thing to what I need that I found is this github repo link, but the solution does not build.

What I had in mind is making an ASP.NET MVC Website where clients (3rd parties) can register themselves and acquire their Client ID's. With ASP.NET API I wanted to create the API that take the required tokens and parameters, and then access the Dyn AX services.

Is this correct or am I entirely wrong? Any help or links regarding building your own oauth2 server/service would be nice.

Thewickedislick
  • 305
  • 1
  • 4
  • 14
Robin
  • 2,704
  • 7
  • 30
  • 47
  • http://leastprivilege.com/2013/11/13/embedding-a-simple-usernamepassword-authorization-server-in-web-api-v2/ – pomber May 04 '15 at 02:12

4 Answers4

199

There is a brilliant blog post from Taiseer Joudeh with a detailed step-by-step description.

  1. Part 1: Token Based Authentication using ASP.NET Web API 2, Owin, and Identity
  2. Part 2: AngularJS Token Authentication using ASP.NET Web API 2, Owin, and Identity
  3. Part 3: Enable OAuth Refresh Tokens in AngularJS App using ASP .NET Web API 2, and Owin
  4. Part 4: ASP.NET Web API 2 external logins with Facebook and Google in AngularJS app
  5. Part 5: Decouple OWIN Authorization Server from Resource Server
MichaelS
  • 3,809
  • 2
  • 26
  • 33
  • I will look at is but from the chapter names I think it is again not what I search as it focuses on Identity and facebook/ google login identity providers. – Robin Nov 05 '14 at 13:12
  • 3
    Only part 4 is about facebook and google. I implemented my own authentication controller based on these tutorials two months ago. And I was using my own user database too. – MichaelS Nov 05 '14 at 13:19
  • 1
    I have one more question, where do these tokens get stored? Does Identity take care of this entirely? – Robin Nov 06 '14 at 09:18
  • 18
    @MichaelS thanks for referring to my blog posts, glad it was helpful for your project :) – Taiseer Joudeh Nov 15 '14 at 22:47
  • @MichaelS I doubted if the way of Token based authentication is security enough for the rest api . because if I can got the user's token in his browser. I think it can be achieved because token is stored in the request header `Authentication` . I can do everything I want like get / post/ put / delete. – Joe.wang Aug 17 '15 at 15:00
  • @Joe.wang you are right. But it's more secure than cookies. Tokens are save agains CSRF, cookies are not. – MichaelS Aug 20 '15 at 08:43
  • @MichaelS Thank your nice reply, In these days , I was stuck with finding a more security way than the way of token-based. the problem is the server hosting the restful api only can authenticate the client with the user credential . But that is all. nothing else. It doesn't care if the request is from the client who initiate the token request. right ? thanks. – Joe.wang Aug 20 '15 at 15:44
  • @MichaelS Or did I think about too much of it ? Hopefully can get some guide . Thanks . – Joe.wang Aug 20 '15 at 15:46
  • @Joe.wang Unfortunately there is no 100% security. An attacker has to compromise your website with XSS to get the token. It's your turn to prevent that. And using TLS reduces the risk of a Man-in-the-middle attack. Do you see other risks? – MichaelS Aug 21 '15 at 07:35
  • @MichaelS I mean , We should know what exactly component (code or application)should take the responsibility to take care of the every aspect of security. It seems token based authentication implemented with code is just take care of the security of business level. not the application level security like what you mentioned XSS and Man-in-the-middle it should take care. So Is it necessary to take all the issues into consideration when we still in the code level? My thought is we should consider the XSS , Man-in-middle issue in the deployment of our application. not in the code level. Thanks. – Joe.wang Aug 21 '15 at 07:48
  • I tried to login with google... but failed with Error: redirect_uri_mismatch. @TaiseerJoudeh your blog wasted my valuable time.. ;( – Nisar Sep 07 '15 at 11:55
  • Finally i am using Hello.js in NODE for asp.net – Nisar Sep 07 '15 at 12:02
  • Every example I see is using Entity Framework. I want to know how to build that part too. – Ryan Mann Dec 08 '15 at 04:42
  • I'd love to see an example of using AD/LDAP for user login over (instead of) Identity. Also, some discussion about whether or not you should keep a store of active tokens on the server for expiration checking. – Scott Fraley Jun 14 '16 at 15:49
  • @MichaelS - How did you decouple OAuth from ASP.NET Identity? I am looking to do the same thing as you described ... using my own authentication. – webworm Jun 28 '16 at 17:40
  • Oh No! When following the links I get "Notice: Undefined offset: 0 in /home/customer/www/bitoftech.net/public_html/wp-content/plugins/crayon-syntax-highlighter/crayon_formatter.class.php on line 532" – RikRak Jul 13 '21 at 20:21
94

I also struggled finding articles on how to just generate the token part. I never found one and wrote my own. So if it helps:

The things to do are:

  • Create a new web application
  • Install the following NuGet packages:
    • Microsoft.Owin
    • Microsoft.Owin.Host.SystemWeb
    • Microsoft.Owin.Security.OAuth
    • Microsoft.AspNet.Identity.Owin
  • Add a OWIN startup class

Then create a HTML and a JavaScript (index.js) file with these contents:

var loginData = 'grant_type=password&username=test.test@mail.com&password=test123';

var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
    if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
        alert(xmlhttp.responseText);
    }
}
xmlhttp.open("POST", "/token", true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.send(loginData);
<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    <script type="text/javascript" src="index.js"></script>
</body>
</html>

The OWIN startup class should have this content:

using System;
using System.Security.Claims;
using Microsoft.Owin;
using Microsoft.Owin.Security.OAuth;
using OAuth20;
using Owin;

[assembly: OwinStartup(typeof(Startup))]

namespace OAuth20
{
    public class Startup
    {
        public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }

        public void Configuration(IAppBuilder app)
        {
            OAuthOptions = new OAuthAuthorizationServerOptions()
            {
                TokenEndpointPath = new PathString("/token"),
                Provider = new OAuthAuthorizationServerProvider()
                {
                    OnValidateClientAuthentication = async (context) =>
                    {
                        context.Validated();
                    },
                    OnGrantResourceOwnerCredentials = async (context) =>
                    {
                        if (context.UserName == "test.test@mail.com" && context.Password == "test123")
                        {
                            ClaimsIdentity oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
                            context.Validated(oAuthIdentity);
                        }
                    }
                },
                AllowInsecureHttp = true,
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(1)
            };

            app.UseOAuthBearerTokens(OAuthOptions);
        }
    }
}

Run your project. The token should be displayed in the pop-up.

Okan Kocyigit
  • 13,203
  • 18
  • 70
  • 129
Kai Hartmann
  • 3,106
  • 1
  • 31
  • 45
  • 7
    I really like how you didn't bring in ASP Identity or Entity Framework. Most articles I have seen integrate these with the OAuth solution. Your solution focuses on OAuth and the issuance of the token. Very nice. Thanks also for posting on your blog. – webworm Jun 27 '16 at 21:11
  • @Kai - Where does `Microsoft ASP.NET Identity Owin` come into play? Are you using ASP.NET Identity for your user authentication? If not, is this NuGet package still needed? – webworm Jun 28 '16 at 14:39
  • 1
    @webworm - The line `app.UseOAuthBearerTokens(OAuthOptions);` wont work without `Microsoft ASP.NET Identity Owin`. It does not recognize the method `UseOAuthBearerTokens`. – Kai Hartmann Jun 29 '16 at 06:32
  • missing package : Microsoft.Owin.Host.SystemWeb, Microsoft ASP.NET Identity Owin – Muhammed Afsal Dec 15 '17 at 07:36
  • 3
    I just want to add one thing i.e if you too are getting Newtonsoft.Json invalid assembly error (in .NET 4.6 and above) then please update Newtonsoft.Json to version 11 or above. – vibs2006 Mar 22 '18 at 15:11
5

I am researching the same thing and stumbled upon identityserver which implements OAuth and OpenID on top of ASP.NET. It integrates with ASP.NET identity and Membership Reboot with persistence support for Entity Framework.

So, to answer your question, check out their detailed document on how to setup an OAuth and OpenID server.

Korayem
  • 12,108
  • 5
  • 69
  • 56
-10

Gmail: OAuth

  • Goto the link
  • Login with your gmail username password
  • Click on the google menu at the top left
  • Click API Manager
  • Click on Credentials
  • Click Create Credentials and select OAuth Client
  • Select Web Application as Application type and Enter the Name-> Enter Authorised Redirect URL (Eg: http://localhost:53922/signin-google) ->Click on Create button. This will create the credentials. Pls make a note of Client ID and Secret ID. Finally click OK to close the credentials pop up.
  • Next important step is to enable the Google API. Click on Overview in the left pane.
  • Click on the Google API under Social APIs section.
  • Click Enable.

That’s all from the Google part.

Come back to your application, open App_start/Startup.Auth.cs and uncomment the following snippet

        app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
        {
            ClientId = "",
            ClientSecret = ""
        });

Update the ClientId and ClientSecret with the values from Google API credentials which you have created already.

  • Run your application
  • Click Login
  • You will see the Google button under ‘Use Another Section to log in’ section
  • Click on the Google button
  • Application will prompt you to enter the username and password
  • Enter the gmail username and password and click Sign In
  • This will perform the OAuth and come back to your application and prompting you to register with the Gmail id.
  • Click register to register the Gmail id into your application database.
  • You will see the Identity details appear in the top as normal registration
  • Try logout and login again thru Gmail. This will automatically logs you into the app.
Michael
  • 1,453
  • 3
  • 20
  • 28
  • 16
    The user is explicitally stating that he doesn't want to use Facebook or Gmail logins. – Bartho Bernsmann May 06 '16 at 14:59
  • 1
    I don't think it's necessary to downvote this answer. An upvote on the top comment is sufficient. This answer contains useful information, and the answer-er expended real creative effort to provide said information. `Why punish that effort?` Perhaps SO needs a way to flag an answer as misalligned to OPs question. Or to allow users to suggest it be moved to a more approprate question ... or to create a new question from the answer. – Walter Stabosz May 06 '20 at 14:50