Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Webapi with multiple oauth tokens for different users

I am in the process of creating my own webapi in asp.net using oauth as authorization provider. The api wil basically serve as a provider for different modules as i call them. One could be a image gallery, the other could just be a user login module with different types of users.

I have the oauth part working fine. Api users can register and then ask for a Token by calling the /Token endpoint with the login credentials.

However i now want to create another seperate user module in the api that is only accessible by apiusers that registered . I want this module to have another register and login function and have their own endpoint to login (/UserModuleToken or something like that). The users coming from the user module are different users than the Api users. So the apiusers are the actual developers that want to call specific modules in my api, and the users from the user module are users that register on the site where that module is implemented.

All of my apicontrollers wil have the [Authorize] attribute for the api user, and i want specific ones, for example some function in the user module, to be decorated with [UserModuleAuthorize] attribute.

Below you can see my api user entity model:

public class ApiUserEntity : BaseEntity
{
    public string Username { get; set; }
    public string Password { get; set; }
    public string Email { get; set; }
    public string Salt { get; set; }
    public ApiUserLevel Level { get; set; }
}

The userservice function that can validate an api user:

public UserLoginResult LoginUser(ApiUserEntityLoginForm userForm)
{
    // retrieve user from database
    var user = _userRepository.GetUser(userForm.UserName);

    if(user == null)
        return _modelStateWrapper.AddError(UserLoginResult.UserNotFound, "User does not exist");

    var passwordHash = PasswordHash.HashPassword(user.Salt, userForm.Password);

    // check if password matches with database.
    if (passwordHash != user.Password)
        return _modelStateWrapper.AddError(UserLoginResult.IncorrectPassword, "Incorrect password");

    return UserLoginResult.Success;
}

And calling the /Token endpoint in my webapi will call the following function of the token provider:

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{

    context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

    // create a userloginform object : 
    var loginForm = new ApiUserEntityLoginForm {UserName = context.UserName, Password = context.Password};

    // pass it into the login validation function of the userservice:
    var loginResult = _userService.LoginUser(loginForm);

    // if login result was not sucesful, return an error.
    if (loginResult != UserLoginResult.Success)
    {
        var jsonSerialiser = new JavaScriptSerializer();
        var json = jsonSerialiser.Serialize(_userService.Errors());

        context.SetError("invalid_grant", json);
        return;
    }

    // result was succesful, grant the token.
    var identity = new ClaimsIdentity(context.Options.AuthenticationType);
    identity.AddClaim(new Claim("sub", context.UserName));
    identity.AddClaim(new Claim("role", "user"));

    context.Validated(identity);

}

i configure my oauth provider and define the /Token endpoint with the following function:

public static void ConfigureOAuth(IAppBuilder app, IUnityContainer container)
{

    var simpleAuthorizationServerProvider = container.Resolve<SimpleAuthorizationServerProvider>();

    var OAuthServerOptions = new OAuthAuthorizationServerOptions()
    {
        AllowInsecureHttp = true,
        TokenEndpointPath = new PathString("/token"),
        AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
        Provider = simpleAuthorizationServerProvider
    };

    // Token Generation
    app.UseOAuthAuthorizationServer(OAuthServerOptions);
    app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

}

Now my question is if it is somehow possible to have multiple token endpoints so i can have a token for apiusers and then another one for a user that is using the custom user module and protect certain functionality based on those 2 users.

I couldnt find any information about this after an extensive amount of searching the internet. So im beginning to believe this is not good practice or not possible. If anyone would be able to point me in the right direction that would be great!

like image 216
Jurgen Welschen Avatar asked Dec 20 '22 10:12

Jurgen Welschen


1 Answers

Well I believe you need to configure users authorization based on Roles, what you are trying to do is just complicating your solution. What you can do is the following: inside method GrantResourceOwnerCredentials you need to obtain the correct role(s) for the authenticated user from the DB store i.e "Admin" and then add them as claims with type "Role" as the code below:

identity.AddClaim(new Claim(ClaimTypes.Role, "Admin"));
identity.AddClaim(new Claim(ClaimTypes.Role, "Supervisor"));

Now on your controllers that you want just user with role "Admin" to access; you need to attribute with [Authorize(Roles="Admin")] or maybe multiple roles [Authorize(Roles="Admin,User")]

This is the straightest way to achive your goal.

Btw this code from http://bitoftech.net, right? Glad to see my code samples used :) Let me know if you need further clarifications.

like image 119
Taiseer Joudeh Avatar answered Dec 21 '22 23:12

Taiseer Joudeh