3
votes

Sorry if this question is poorly worded, I am new to authentication.

I have an ASP.NET MVC project that serves my web frontend and this is authenticated using OWIN and identity cookie based authentication. This seems to work fine independently of my Web API.

I also have an ASP.NET Web API project that is also authenticated using OWIN and identity token based authentication e.g. make a request to the /Token endpoint and get a bearer token that can be used to make requests to the API endpoints. This works fine when called via postman using the bearer token generated via the /Token endpoint, but as I don't have the password when I want to call the API from the MVC application, I can't use the token endpoint to generate a token.

My problem is I would like to be able to make requests to the ASP.NET Web API from my authenticated ASP.NET MVC application, how would I go about generating a token that I can call the Web API? Given that I have a ClaimsIdentity that has been authenticated.

My Startup.Auth for my MVC project is:

public partial class Startup 
{
    public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context, user manager and signin manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
        app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);

        // Enable the application to use a cookie to store information for the signed in user
        // and to use a cookie to temporarily store information about a user logging in with a third party login provider
        // Configure the sign in cookie
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider
            {
                // Enables the application to validate the security stamp when the user logs in.
                // This is a security feature which is used when you change a password or add an external login to your account.  
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
            }
        });            
    }
}

My Startup.Auth for my Web API project is:

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

    public static string PublicClientId { get; private set; }

    // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
    public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context and user manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

        // Configure the application for OAuth based flow
        PublicClientId = "self";
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(PublicClientId),
            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
            // In production mode set AllowInsecureHttp = false
            AllowInsecureHttp = true
        };

        // Enable the application to use bearer tokens to authenticate users
        app.UseOAuthBearerTokens(OAuthOptions);
    }
}

Thank you and please let me know if there's any further information that would be useful.

1

1 Answers

2
votes

One option to consider, that I've implemented before, is to retrieve a token from the API upon successful login from the MVC application - using the same credentials that were passed in during login. Store the token how you please (i.e. in ASP.NET Session State) then use it as necessary in your application.

Your MVC application Login controller action could look something like this:

var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: true);

switch (result)
{
    case SignInStatus.Success:

        BearerToken token;

        using (var httpClient = new HttpClient())
        {
            var tokenRequest =
                new List<KeyValuePair<string, string>>
                    {
                        new KeyValuePair<string, string>("grant_type", "password"),
                        new KeyValuePair<string, string>("username", model.Email),
                        new KeyValuePair<string, string>("password", model.Password)
                    };

            HttpContent encodedRequest = new FormUrlEncodedContent(tokenRequest);

            HttpResponseMessage response = httpClient.PostAsync("https://YourWebApiEndpoint/Token", encodedRequest).Result;
            token = response.Content.ReadAsAsync<BearerToken>().Result;

            // Store token in ASP.NET Session State for later use
            Session["ApiAccessToken"] = token.AccessToken;
        }

        return RedirectToAction("SomeAction", "SomeController");
}

BearerToken is just a bespoke class representation of the full API token structure:

public class BearerToken
{
    [JsonProperty("access_token")]
    public string AccessToken { get; set; }

    [JsonProperty("token_type")]
    public string TokenType { get; set; }

    [JsonProperty("expires_in")]
    public string ExpiresIn { get; set; }

    [JsonProperty("userName")]
    public string UserName { get; set; }

    [JsonProperty(".issued")]
    public string Issued { get; set; }

    [JsonProperty(".expires")]
    public string Expires { get; set; }
}

An example call from the MVC application to retrieve some data might then look like this:

using (var httpClient = new HttpClient())
{
    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Session["ApiAccessToken"].ToString());

    var response = httpClient.GetAsync("https://YourWebApiEndpoint/SomeController/SomeGetAction").Result;

    // Do something with response...
}