Token based authentication for both Web App and We

2019-06-07 18:46发布

问题:

Scenario: Both Web application and Web API need to be authenticated and protected from the server side.

Requirement: Web application is serving the contents for the browser and browser should be calling Web API directly (i.e. Browser to API).

Question: Is it possible to authenticate both Web APP and the API using tokens?

Any sample code or clear direction would be highly appreciated.


Normally web applications are authenticated using cookies and APIs are authenticated using tokens.There are some sample projects available here but they are either browser to API (SPA token based) or Server side Web App calling API from server to server.

UPDATE 1

App is saving the TokenValidationParameters and used bootstrapContext.Token within the app controller to grab for server to server communication.

As per @dstrockis, I'm trying to grab the id_token from the Web App soon after the end of validation (not within the app contrller).

I'm using SecurityTokenValidated invoker in OpenIdConnectAuthenticationOptions.Notifications within the Startup class. SecurityTokenValidated receives a parameter of type SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> but I'm not sure where to find the id_token within it. Method is below.

private OpenIdConnectAuthenticationOptions CreateOptionsFromPolicy(string policy)
{
    return new OpenIdConnectAuthenticationOptions
    {
        // For each policy, give OWIN the policy-specific metadata address, and
        // set the authentication type to the id of the policy
        MetadataAddress = String.Format(aadInstance, tenant, policy),
        AuthenticationType = policy,

        // These are standard OpenID Connect parameters, with values pulled from web.config
        ClientId = clientId,
        RedirectUri = redirectUri,
        PostLogoutRedirectUri = redirectUri,
        Notifications = new OpenIdConnectAuthenticationNotifications
        {
            AuthenticationFailed = OnAuthenticationFailed,

            //NEW METHOD INVOKE ************************************
            //******************************************************
            SecurityTokenValidated = OnSecurityTokenValidated

            //******************************************************
        },
        Scope = "openid",
        ResponseType = "id_token",

        TokenValidationParameters = new TokenValidationParameters
        {
            NameClaimType = "name",
            SaveSigninToken = true
        },
    };
}



//NEW METHOD ************************************
private Task OnSecurityTokenValidated(
       SecurityTokenValidatedNotification<OpenIdConnectMessage,
                       OpenIdConnectAuthenticationOptions> arg)
{
    //QUESTION ********************************************************
    //How to find the just saved id_token using incoming parameter, arg
    //*****************************************************************

    return Task.FromResult(0);
}

UPDATE 2

Instead of SecurityTokenValidated, I tried AuthorizationCodeReceived and it's not getting called at all. As discussed here, my redirect url does have an ending slash as well.

Any Ideas?

回答1:

Our ASP.NET OpenID Connect middleware which supports AAD B2C is built to rely on cookie authentication from a browser. It doesn't accept tokens in a header or anything like that for securing web pages. So I'd say if you want to serve HTML from your web app in the classic way, you need to use cookies to authenticate requests to the web app.

You can definitely get & store tokens within the browser and use those to access your web API, even if you use cookies to authenticate to the web app. There's two patterns I'd recommend:

  • Perform the initial login using the OpenID Connect Middleware, initiating the flow from the server side as described in the samples. Once the flow completes, the middleware will validate the resulting id_token and drop cookies in the browser for future requests. You can instruct the middleware to save the id_token for later use by using the line of code written here. You can then somehow pass that id_token down to your browser, cache it, and use it to make requests to the API.
  • The other pattern is the inverse. Start by initiating the login from javascript, using the single page app pattern from the B2C documentation. Cache the resulting id_tokens in the browser, and use them to make API calls. But when the login completes, you can send a request to your web app with the id_token in the body, triggering the OpenID Connect middleware to process the request and issue a session cookie. If you want to know the format of that request, I'd recommend inspecting a regular server side OpenID Connect flow.


回答2:

Found the answer to my own question and adding here for the future reference.

After a successful validation, id_token can be accessed by invoking the SecurityTokenValidated notification. Code sample is below.

private Task OnSecurityTokenValidated(
       SecurityTokenValidatedNotification<OpenIdConnectMessage,
                       OpenIdConnectAuthenticationOptions> arg)
{
    //Id Token can be retrieved as below.
    //**************************************
    var token = arg.ProtocolMessage.IdToken;

    return Task.FromResult(0);
}

However, saving this directly into a browser cookie may not be secure.