Shivram Raj
Shivram Raj

Reputation: 1

MSIS9649: Received invalid OAuth request. The 'assertion' parameter value is not a valid access token

I am trying to implement ADFS4 - OAuth (OpenID connect) for authentication and webapp to webapi communication.

I have configured ADFS application group accordingly and use OpenIdconnectauth pipeline in webapp for authentication. In order to call webapi, if I request accesstoken using just client credential grant, it works fine as I receive the valid access token and able to get to the api. However, the access token does not have any user details in it which I need it from the webapi end.

So, then I tried by creating UserAssertion object from bootstrapcontext.token. But this time, when ever I request access token, I receive this error as mentioned in the title.

Here is the code snippet:

AuthenticationContext authContext = null;
AuthenticationResult result = null;
authContext = new AuthenticationContext(Startup.authority, false);
ClientCredential credential = new ClientCredential(Startup.clientId, Startup.appKey);
string usercheck = User.Identity.Name; //For checking, returns username

var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;
string username = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn) != null ? ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn).Value : ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
string userAccessToken = bootstrapContext.Token;
UserAssertion userAssertion = new UserAssertion(bootstrapContext.Token, "urn:ietf:params:oauth:grant-type:jwt-bearer", username);

string accessToken = null;
HttpClient httpClient = new HttpClient();

try {
//result = authContext.AcquireTokenAsync(Startup.apiResourceId, credential).Result; // This works fine but no user details in the token
 result = authContext.AcquireTokenAsync(Startup.apiResourceId, credential, userAssertion).Result;
}

Here is how the Startup.ConfigureAuth(IAppBuilder app) looks like in both webapp and webapi:

In webapp:

public void ConfigureAuth(IAppBuilder app)
{
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

            app.UseCookieAuthentication(new CookieAuthenticationOptions());

            app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    ClientId = clientId,
                    AuthenticationType = OpenIdConnectAuthenticationDefaults.AuthenticationType,

                    MetadataAddress = metadataAddress,
                    PostLogoutRedirectUri = postLogoutRedirectUri,
                    RedirectUri = postLogoutRedirectUri,
                    TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters()
                    {
                        SaveSigninToken = true
                    },

                    ResponseType = "code id_token",
                    Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        AuthenticationFailed = context =>
                        {
                            context.HandleResponse();
                            context.Response.Redirect("/Error?message=" + context.Exception.Message);
                            return Task.FromResult(0);
                        }
                    }
                });
}

And in webapi:

public void ConfigureAuth(IAppBuilder app)
        {
            JwtSecurityTokenHandler.InboundClaimTypeMap.Clear();
            app.UseActiveDirectoryFederationServicesBearerAuthentication(
                new ActiveDirectoryFederationServicesBearerAuthenticationOptions
                {
                    MetadataEndpoint = ConfigurationManager.AppSettings["ida:AdfsMetadataEndpoint"],
                    TokenValidationParameters = new TokenValidationParameters() {
                        SaveSigninToken = true,
                        ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
                    }
                });
        }

I reckon that the token that I am passing in to the userassertion is incorrect. But how can I fix this? Is there any other way which I can get the user details in to the access token. I really appreciate if anyone can help us to solve this issue?

Thanks.

Upvotes: 0

Views: 1560

Answers (1)

mcdaniel_ws
mcdaniel_ws

Reputation: 11

You have to use authorization code flow to get the MVC app to talk to the API. Vittorio has a nice post on it here, although it talks about azure.

In order to do that you need to handle the AuthorizationCodeReceived Event via Notifications on the OpenIdConnectAuthenticationOptions from Startup.ConfigureAuth(IAppBuilder app)

app.UseOpenIdConnectAuthentication(
    new OpenIdConnectAuthenticationOptions {
       ...
       Notifications = new OpenIdConnectAuthenticationNotifications {
           AuthorizationCodeReceived = async code => {
               ClientCredential credential = new ClientCredential(Startup.clientId, Startup.appKey);
               AuthenticationContext authContext = new AuthenticationContext(Startup.authority, false);
               AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(
                   code.Code,
                   new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), 
                   credential, 
                   Startup.apiResourceId);
           }
       }

When you are ready to make the call you acquire your token silently.

var authContext = new AuthenticationContext(Startup.authority, false);
var credential = new ClientCredential(Startup.clientId, Startup.appKey);
var claim = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
var userId = new UserIdentifier(claim, UserIdentifierType.UniqueId);

result = await authContext.AcquireTokenSilentAsync(
    Startup.apiResourceId,
    credential,
    userId);

HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
    "Bearer", 
    result.AccessToken);

Upvotes: 1

Related Questions