Authorization Code Flow Error in ASP.Net Form using Owin Starup - owin

We are implementing Azure SSO in Traditional ASP.Net Web Application and we want to implement Authorization Code Flow for generating Refresh, Access and Id Tokens.
We have implemented the below code in AuthorizationCodeReceived function of the owin's app.UseOpenIdConnectAuthentication class. From the below mentioned code we are able to successfully fetch the Refreshtoken, AccessToken and IdToken.
But notification.AuthenticationTicket is null and it throws null reference excpetion so we are not able to add the claims for id and access tokens.
Also in the aspx.cs file the HttpContext.Current.User.Identity.IsAuthenticated is returned as false even after generating all the 3 tokens.
Please suggest why notification.AuthenticationTicket is null inside AuthorizationCodeReceived event and what changes we have to do inside AuthorizationCodeReceived event to make HttpContext.Current.User.Identity.IsAuthenticated as "true".
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseKentorOwinCookieSaver();
app.UseCookieAuthentication(new CookieAuthenticationOptions());
Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolValidator dd = new Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolValidator();
dd.RequireNonce = false;
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
ClientSecret = clientSecret,
PostLogoutRedirectUri = redirectUri,
RedirectUri = redirectUri,
Scope = "openid profile email offline_access",
ResponseType = OpenIdConnectResponseType.Code,
SignInAsAuthenticationType = "Cookies",
Notifications = new OpenIdConnectAuthenticationNotifications()
{
AuthenticationFailed = (context) =>
{
return System.Threading.Tasks.Task.FromResult(0);
},
AuthorizationCodeReceived = async notification =>
{
using (var client = new HttpClient())
{
var configuration = await notification.Options.ConfigurationManager.GetConfigurationAsync(notification.Request.CallCancelled);
var request = new HttpRequestMessage(HttpMethod.Post, configuration.TokenEndpoint);
request.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
[OpenIdConnectParameterNames.ClientId] = notification.Options.ClientId,
[OpenIdConnectParameterNames.ClientSecret] = notification.Options.ClientSecret,
[OpenIdConnectParameterNames.Code] = notification.ProtocolMessage.Code,
[OpenIdConnectParameterNames.GrantType] = "authorization_code",
[OpenIdConnectParameterNames.RedirectUri] = notification.Options.RedirectUri
});
var response = await client.SendAsync(request, notification.Request.CallCancelled);
response.EnsureSuccessStatusCode();
var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
notification.AuthenticationTicket.Identity.AddClaim(new Claim(
type: OpenIdConnectParameterNames.AccessToken,
value: payload.Value<string>(OpenIdConnectParameterNames.AccessToken)));
notification.AuthenticationTicket.Identity.AddClaim(new Claim(
type: OpenIdConnectParameterNames.IdToken,
value: payload.Value<string>(OpenIdConnectParameterNames.IdToken)));
}
},
// Attach the id_token stored in the authentication cookie to the logout request.
RedirectToIdentityProvider = notification =>
{
if (notification.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
{
var token = notification.OwinContext.Authentication.User?.FindFirst(OpenIdConnectParameterNames.IdToken);
if (token != null)
{
notification.ProtocolMessage.IdTokenHint = token.Value;
}
}
return Task.CompletedTask;
},
SecurityTokenValidated = (context) =>
{ if (context != null)
{
if (context.ProtocolMessage != null && !string.IsNullOrEmpty(context.ProtocolMessage.IdToken))
{
context.AuthenticationTicket.Identity.AddClaim(new Claim("IdToken", context.ProtocolMessage.IdToken));
}
}
return Task.FromResult(0);
}
}
}
);

Related

Unable to redirect uri after cas authentication with WSO2 provider using asp.net core authorization

[enter image description here][1]I am trying to authenticate my .net core application using cas with Wso2 identity provider although the autentication is succesful but on redirect uri i am getting webpage not found error with cas ticket not able to figure out what is the issue any guidance would be helpful
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Login";
options.Events.OnSigningOut = context =>
{
var redirectContext = new RedirectContext<CookieAuthenticationOptions>(
context.HttpContext,
context.Scheme,
context.Options,
context.Properties,
"/"
);
if (builder.Configuration.GetValue("Authentication:CAS:SingleSignOut", false))
{
// Single Sign-Out
var casUrl = new Uri(builder.Configuration["Authentication:CAS:ServerUrlBase"]);
var links = context.HttpContext.RequestServices.GetRequiredService<LinkGenerator>();
var serviceUrl = context.Properties.RedirectUri ?? links.GetUriByPage(context.HttpContext, "/Index");
redirectContext.RedirectUri = UriHelper.BuildAbsolute(
casUrl.Scheme,
new HostString(casUrl.Host, casUrl.Port),
casUrl.LocalPath, "/logout",
QueryString.Create("service", serviceUrl!));
}
context.Options.Events.RedirectToLogout(redirectContext);
return Task.CompletedTask;
};
})
.AddCAS(o =>
{
o.CasServerUrlBase = builder.Configuration["Authentication:CAS:ServerUrlBase"]; // Set in `appsettings.json` file.
o.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.CasValidationUrl = "/";
});
Login controller
[HttpGet("login")]
public IActionResult Login(string returnUrl)
{
// var props = new AuthenticationProperties { RedirectUri = "/" };
return Challenge(new AuthenticationProperties { RedirectUri = returnUrl }, "CAS");
// return Redirect("http://localhost:5095/");
}
[Web Response](https://i.stack.imgur.com/1LFOP.png)
[1]: https://i.stack.imgur.com/v3fKm.png

Both OIDC and ADFS in same application (OWIN)

I am working on an ASP.NET MVC 5 website using EPiServer CMS.
The requirement is that we have admin (back-end users) log in using ADFS (working) and OIDC for front-end.
Both are set to passive mode and are called through action methods in a controller.
The issue I am facing is that front-end users OIDC is set to (Authentication type ="Federation") when it returns from external call instead of external cookie.
public void Configuration(IAppBuilder app)
{
//IdentityModelEventSource.ShowPII = true;
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;
ConfigureMemberAuth(app);
ConfigureAdminAuth(app);
}
private void ConfigureMemberAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/logmein/"),
LogoutPath = new PathString("/"),
AuthenticationMode = AuthenticationMode.Active
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
_ = app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = ApplicationSettings.OIDCClientId,
ClientSecret = ApplicationSettings.OIDCClientSecret,
Authority = ApplicationSettings.OIDCAuthority,
RedirectUri = $"{ApplicationSettings.Domain}{_oidcRedirectMethod}",
PostLogoutRedirectUri = ApplicationSettings.Domain,
ResponseType = OpenIdConnectResponseType.CodeIdToken,
Scope = "xxx",
SaveTokens = true,
AuthenticationMode = AuthenticationMode.Passive,
AuthenticationType = OpenIdConnectAuthenticationDefaults.AuthenticationType,
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = notification =>
{
if (string.Equals(notification.ProtocolMessage.Error, "xxx", StringComparison.Ordinal))
{
notification.HandleResponse();
if (string.Equals(notification.ProtocolMessage.ErrorDescription, "xxx", StringComparison.Ordinal))
notification.Response.Redirect(ApplicationSettings.Domain);
else
{
var errorPage = UrlResolver.GetUrl(PageHelper.GetAdminPage().LoginBox.NemIDErrorPage.GetFriendlyUrl());
notification.Response.Redirect(errorPage);
}
}
return Task.CompletedTask;
},
// Retrieve an access token from the remote token endpoint
// using the authorization code received during the current request.
AuthorizationCodeReceived = async notification =>
{
using (var client = new HttpClient())
{
var configuration = await notification.Options.ConfigurationManager.GetConfigurationAsync(notification.Request.CallCancelled);
var tokenEndpointResult = await ExchangeCodeForTokens(notification, client, configuration);
// Add the identity token to the returned ClaimsIdentity to make it easier to retrieve.
notification.AuthenticationTicket.Identity.AddClaim(new Claim(
type: OpenIdConnectParameterNames.IdToken,
value: tokenEndpointResult.Value<string>(OpenIdConnectParameterNames.IdToken)));
// Retrieve the claims from UserInfo endpoint using the access token as bearer token.
var accesstoken = tokenEndpointResult.Value<string>(OpenIdConnectParameterNames.AccessToken);
var userInfoEndpointResult = await UserInfoEndpointClaims(notification, client, configuration, accesstoken);
//Security note: It is important to verify that the sub claim from ID token matches the sub claim in the UserInfo response
var userinfoSub = userInfoEndpointResult["xx"].Value<string>();
var idtokenSub = notification.AuthenticationTicket.Identity.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier").Value;
if (userinfoSub == idtokenSub)
{
//add claims from UserInfo endpoint to identity
foreach (var entry in userInfoEndpointResult)
{
if (!notification.AuthenticationTicket.Identity.HasClaim(c => c.Type == entry.Key))
{
notification.AuthenticationTicket.Identity.AddClaim(new Claim(
type: entry.Key,
value: entry.Value.ToString()));
}
}
// Add access token to claims.
notification.AuthenticationTicket.Identity.AddClaim(new Claim(
OpenIdConnectParameterNames.AccessToken,
accesstoken));
}
}
},
// Attach the id_token stored in the authentication cookie to the logout request.
RedirectToIdentityProvider = notification =>
{
if (notification.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
{
var token = notification.OwinContext.Authentication.User?.FindFirst(OpenIdConnectParameterNames.IdToken);
if (token != null)
{
notification.ProtocolMessage.IdTokenHint = token.Value;
}
notification.Response.Redirect(ApplicationSettings.Domain);
}
return Task.CompletedTask;
},
}
});
}
private void ConfigureAdminAuth(IAppBuilder app)
{
//Enable cookie authentication, used to store the claims between requests
app.SetDefaultSignInAsAuthenticationType(WsFederationAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType,
CookieName = WsFederationAuthenticationDefaults.CookieName,
AuthenticationMode = AuthenticationMode.Active,
CookieHttpOnly = true,
});
//Enable federated authentication
_ = app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions()
{
//Trusted URL to federation server meta data
MetadataAddress = ApplicationSettings.MetaDataAddress,
//Value of Wtreal must *exactly* match what is configured in the federation server
Wtrealm = ApplicationSettings.RelyPartyUri,
AuthenticationMode = AuthenticationMode.Passive,
Notifications = new WsFederationAuthenticationNotifications()
{
RedirectToIdentityProvider = (ctx) =>
{
// To avoid a redirect loop to the federation server send 403 when user is authenticated but does not have access
if (ctx.OwinContext.Response.StatusCode == 401 && (ctx.OwinContext.Authentication.User.Identity.AuthenticationType == WsFederationAuthenticationDefaults.AuthenticationType && ctx.OwinContext.Authentication.User.Identity.IsAuthenticated))
{
ctx.OwinContext.Response.StatusCode = 403;
ctx.HandleResponse();
}
//XHR requests cannot handle redirects to a login screen, return 401
if (ctx.OwinContext.Response.StatusCode == 401 && IsXhrRequest(ctx.OwinContext.Request))
{
ctx.HandleResponse();
}
return Task.FromResult(0);
},
SecurityTokenValidated = (ctx) =>
{
//Ignore scheme/host name in redirect Uri to make sure a redirect to HTTPS does not redirect back to HTTP
var redirectUri = new Uri(ctx.AuthenticationTicket.Properties.RedirectUri, UriKind.RelativeOrAbsolute);
if (redirectUri.IsAbsoluteUri)
{
ctx.AuthenticationTicket.Properties.RedirectUri = redirectUri.PathAndQuery;
}
//Sync user and the roles to EPiServer in the background
ServiceLocator.Current.GetInstance<ISynchronizingUserService>().SynchronizeAsync(ctx.AuthenticationTicket.Identity);
return Task.FromResult(0);
},
}
});
//Add stage marker to make sure WsFederation runs on Authenticate (before URL Authorization and virtual roles)
app.UseStageMarker(PipelineStage.Authenticate);
// Remap logout to a federated logout
app.Map(LogoutUrl, map =>
{
map.Run(ctx =>
{
ctx.Authentication.SignOut();
ctx.Response.Redirect(ApplicationSettings.Domain);
return Task.FromResult(0);
});
});
}
When I out comment this line: app.SetDefaultSignInAsAuthenticationType(WsFederationAuthenticationDefaults.AuthenticationType);
in admin auth then client-login works as intended and authentication type is set to "ExternalCookie" when call return but then admin login stops working ?
Any help would be appreciated

HttpContext.Request.IsAuthenticated is false in Ajax request + OpenID Connect Cookie based validation

We are using OpenIdConnect based authentication in the asp.net mvc application. Initial login is working fine. But when we use the Ajax call to invoke the action method, User is coming as not authenticated. I checked in Custom Authorization - HttpContext.Request.IsAuthenticated is coming as false.
I checked the cookie ".AspNet.Cookies" and it has the value. Why is open ID not authenticating the user.
Below is my authentication code
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = AuthenticationConfig.ClientId,
Authority = AuthenticationConfig.AADInstance + AuthenticationConfig.TenantId,
PostLogoutRedirectUri = AuthenticationConfig.PostLogoutRedirectURI,
RedirectUri = AuthenticationConfig.RedirectUri,
Scope = OpenIdConnectScope.OpenIdProfile,
ResponseType = OpenIdConnectResponseType.Code,
SaveTokens = true,
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(AuthenticationConfig.ClientSecret)),
ValidateIssuer = true,
ValidIssuer = AuthenticationConfig.AADInstance + AuthenticationConfig.TenantId + "/v2.0",
},
SignInAsAuthenticationType = "Cookies",
Notifications = new OpenIdConnectAuthenticationNotifications()
{
// when an auth code is received...
AuthorizationCodeReceived = OnAuthorizationCodeReceived,
AuthenticationFailed = OnAuthenticationFailed,
SecurityTokenValidated = async n =>
{
var nid = new ClaimsIdentity(n.AuthenticationTicket.Identity);
//var claimsIdentity = filterContext.HttpContext.User.Identity as ClaimsIdentity;
var user = nid.Claims.Where(r => r.Type == PreferedUserNameClaimType).Select(v => v.Value).FirstOrDefault();
var userRolesroles = GetRolesForUser(user);
//nid.AddClaim(new Claim("expires_at", DateTimeOffset.Now.AddSeconds(int.Parse(n.ProtocolMessage.ExpiresIn)).ToString()));
userRolesroles.ToList().ForEach(ui => nid.AddClaim(new Claim(ClaimTypes.Role, ui)));
// keep the id_token for logout
nid.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
// add access token for sample API
nid.AddClaim(new Claim("access_token", n.ProtocolMessage.AccessToken));
n.AuthenticationTicket = new AuthenticationTicket(
nid,
n.AuthenticationTicket.Properties);
UserService.SetUserInformation(user);
},
RedirectToIdentityProvider = ctx =>
{
bool isAjaxRequest = (ctx.Request.Headers != null && ctx.Request.Headers["X-Requested-With"] == "XMLHttpRequest");
if (ctx.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication)
{
if (isAjaxRequest && ctx.Response.StatusCode == (int)HttpStatusCode.Unauthorized)
{
ctx.Response.Headers.Remove("Set-Cookie");
ctx.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
ctx.HandleResponse();
return Task.FromResult(0);
}
}
return Task.FromResult(0);
}
}
});
}
Usually in asp.net, the ApiControllers has no concept of your Controller's authentication. Depending on the way things are builr, you need to add an Authorization header with a bearer access token to let the API know about the authenticated user.

OWIN Hybrid with IdentityServer 3 Authorization code is too long error

Please, help!!!!
I am trying to follow a Hybrid implementation (Azure AD + Identity Server 3) from here
I am able to get to the AAD, I seem to get authenticated (get user info, etc) and receive a context.code:
When I pass that code into RequestAuthorizationCodeAsync I get an "invalid_grant" and if I look at the client, here is what I see (Authorization Code is too long):
Here is my code:
public class Startup
{
string authority = String.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
public void Configuration(IAppBuilder app)
{
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
RedirectUri = "https://localhost:44300/",
PostLogoutRedirectUri = "https://localhost:44300/",
ResponseType = "code id_token",
Scope = "openid profile read write offline_access",
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
},
SignInAsAuthenticationType = "Cookies",
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async context =>
{
string userObjectID = context.AuthenticationTicket.Identity.FindFirst("oid").Value;
string tenantID = context.AuthenticationTicket.Identity.FindFirst("tid").Value;
string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
context.ProtocolMessage.RedirectUri = appBaseUrl + "/";
context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;
Uri redirectUri = new Uri(context.Request.Uri.GetLeftPart(UriPartial.Path));
string authorizationCode = context.Code;
// use the code to get the access and refresh token
var tokenClient = new TokenClient(
Constants.TokenEndpoint,
clientId,
"secret", AuthenticationStyle.PostValues);
var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(
authorizationCode, context.RedirectUri);
if (tokenResponse.IsError)
{
throw new Exception(tokenResponse.Error);
}
// use the access token to retrieve claims from userinfo
var userInfoClient = new UserInfoClient(
new Uri(Constants.UserInfoEndpoint),
tokenResponse.AccessToken);
var userInfoResponse = await userInfoClient.GetAsync();
// create new identity
var id = new ClaimsIdentity(context.AuthenticationTicket.Identity.AuthenticationType);
id.AddClaims(userInfoResponse.GetClaimsIdentity().Claims);
id.AddClaim(new Claim("access_token", tokenResponse.AccessToken));
id.AddClaim(new Claim("expires_at", DateTime.Now.AddSeconds(tokenResponse.ExpiresIn).ToLocalTime().ToString()));
id.AddClaim(new Claim("refresh_token", tokenResponse.RefreshToken));
id.AddClaim(new Claim("id_token", context.ProtocolMessage.IdToken));
id.AddClaim(new Claim("sid", context.AuthenticationTicket.Identity.FindFirst("sid").Value));
context.AuthenticationTicket = new AuthenticationTicket(
new ClaimsIdentity(id.Claims, context.AuthenticationTicket.Identity.AuthenticationType, "name", "role"),
context.AuthenticationTicket.Properties);
},
RedirectToIdentityProvider = context =>
{
// if signing out, add the id_token_hint
if (context.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
{
var idTokenHint = context.OwinContext.Authentication.User.FindFirst("id_token");
if (idTokenHint != null)
{
context.ProtocolMessage.IdTokenHint = idTokenHint.Value;
}
}
return Task.FromResult(0);
}
}
});
}
}

How to use cookies with Azure AD on behalf of flow to get an access token to another resource

I have two applications using the same azure active directory. App A and App B.
App A uses
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
ClientId = Configuration["Authentication:AzureAd:ClientId"],
Authority = Configuration["Authentication:AzureAd:AADInstance"] + Configuration["Authentication:AzureAd:TenantId"],
ClientSecret = Configuration["Authentication:AzureAd:ClientSecret"],
CallbackPath = Configuration["Authentication:AzureAd:CallbackPath"],
ResponseType = OpenIdConnectResponseType.CodeIdToken,
GetClaimsFromUserInfoEndpoint = true,
SignInScheme = "Cookies",
SaveTokens = true,
Events = new OpenIdConnectEvents
{
OnAuthorizationCodeReceived = OnAuthorizationCodeReceived,
}
});
And i acquire an access to application B api service resource by acquiring the token with:
private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
{
string userObjectId = (context.Ticket.Principal.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;
ClientCredential clientCred = new ClientCredential(Configuration["Authentication:AzureAd:ClientId"], Configuration["Authentication:AzureAd:ClientSecret"]);
AuthenticationContext authContext = new AuthenticationContext(Configuration["Authentication:AzureAd:AADInstance"] + Configuration["Authentication:AzureAd:TenantId"]);
AuthenticationResult authResult = await authContext.AcquireTokenByAuthorizationCodeAsync(
context.ProtocolMessage.Code, new Uri(context.Properties.Items[OpenIdConnectDefaults.RedirectUriForCodePropertiesKey]), clientCred, Configuration["Authentication:AzureAd:GraphResourceId"]);
I'm also using cookies to sign in into app A with:
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationScheme = "Cookies",
AutomaticAuthenticate = true,
AutomaticChallenge = true,
SlidingExpiration = true,
ExpireTimeSpan = TimeSpan.FromHours(1),
Events = new CookieAuthenticationEvents()
{
OnSignedIn = OnSignedIn,
OnSigningIn = OnSigningIn,
OnValidatePrincipal = OnValidatePrincipal
}
});
/* Account Controller SignIn() */
return Challenge(
new AuthenticationProperties {
AllowRefresh = true,
IsPersistent = true,
RedirectUri = "/" }, OpenIdConnectDefaults.AuthenticationScheme);
Now my problem is similar to others where my access token is expiring, but my signin cookie to app a is still valid so the user appears to be logged in fine, although they have no token in the cache.
I've followed suit of other questions and looked to my Cookie event of
Task OnValidatePrincipal(CookieValidatePrincipalContext arg) {
var http = new HttpClient();
var uri = "https://login.microsoftonline.com/<tenant>/oauth2/token";
var client_id = "<my_client_id>";
var scope = "https://graph.microsoft.com/mail.read";
var refresh_token = "<saved_refresh_token_in_cookie_if_SaveTokens = true>";
var redirect_uri = "https://localhost:20352/";
var grant_type = "refresh_token";
var client_secret = "<client_secret_from_azure>";
var body = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("client_id", client_id),
new KeyValuePair<string, string>("scope", scope),
new KeyValuePair<string, string>("refresh_token", refresh_token),
new KeyValuePair<string, string>("redirect_uri", redirect_uri),
new KeyValuePair<string, string>("grant_type", grant_type),
new KeyValuePair<string, string>("client_secret", client_secret)
};
var content = new FormUrlEncodedContent(body);
var result = http.PostAsync(uri, content).Result;
var stringContent = result.Content.ReadAsStringAsync().Result;
JObject jobject = JObject.Parse(stringContent);
var token = jobject["access_token"].Value<string>();
Problem here is I don't know how to get this token back into the default TokenStore that the adal AuthenticationContext uses. We have code deeper that needs to pull from:
_authenticationResult = await authContext.AcquireTokenSilentAsync(_authConfigOptions.AzureAd.WebserviceAppIdUri.ToString(), credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
Is there a way I can get a new resource access token back into the tokenstore for users App B api calls, without a valid token / refresh token 'On Behalf of User' flow?
If you lose the access token and refresh token, you must redirect the user to Azure AD to authenticate again. They may be still authenticated there so they just get redirected back to your app along with the authorization code.
In one of my projects I made an exception filter that does this:
public void OnException(ExceptionContext filterContext)
{
//If the error is a silent token acquisition exception from ADAL..
if(filterContext.Exception is AdalSilentTokenAcquisitionException)
{
//Instead of the usual procedure, return a 401 which triggers the OpenIdConnect middleware redirection
filterContext.Result = new HttpUnauthorizedResult();
filterContext.ExceptionHandled = true;
}
}
So if the exception is thrown where silent token acquisition fails, just swallow the error and change the result into a 401, which triggers the OpenIdConnect middleware to send the user to Azure AD.
Since you have AutomaticAuthenticate=true, it should do this.

Resources