How to use MVC4 Client with IdentityServer4? - asp.net-mvc

Does anyone know how to have MVC 4 client app to use identityserver4 as auth provider?
I have tried the sample codes of identityserver3 but no success. Upon request to [Authorize] action it redirects to identityserver4 probably login end point and gives unknown error.
As far as I know, I am not able to define client at both identityserver4 'start-up.cs' and MVC client with OWIN's 'startup.cs'.
Update
The code from my IdentityServer4 app - MVC 4 Client Definition
// OpenID Connect hybrid flow and client credentials client (MVC)
new Client
{
ClientId = "mvc4",
ClientName = "MVC 4 Client",
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
RequireConsent = false,
ClientSecrets =
{
new Secret("secret".Sha256())
},
RedirectUris = { "http://localhost:53173/signin-oidc" },
PostLogoutRedirectUris = { "http://localhost:53173/signout-callback-oidc" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
},
AllowOfflineAccess = true
}
And the code from 'Startup.cs' of my MVC 4 app
public void Configuration(IAppBuilder app)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap = new Dictionary<string, string>();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "http://localhost:5000/",
RequireHttpsMetadata = false,
ClientId = "mvc4",
ClientSecret = "secret",
ResponseType = "code id_token",
Scope = "openid profile api1 offline_access",
UseTokenLifetime = false,
SignInAsAuthenticationType = "Cookies",
});
}
Update 2
I changed the Startup.cs of my MVC 4 Client to:
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
AuthenticationType = "oidc",
SignInAsAuthenticationType = "Cookies",
Authority = "http://localhost:5000",
RequireHttpsMetadata = false,
RedirectUri = "http://localhost:53173/signin-oidc",
ClientId = "mvc4",
ClientSecret = "secret",
ResponseType = "code id_token"
});
It now presents a login page, logs in the user and then the IdentityServer has gone into never ending loop:
Update 3
public void Configuration(IAppBuilder app)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap = new Dictionary<string, string>();
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
AuthenticationType = "oidc",
SignInAsAuthenticationType = "Cookies",
Authority = "http://localhost:5000",
RequireHttpsMetadata = false,
RedirectUri = "http://localhost:53173/signin-oidc",
ClientId = "mvc4",
ClientSecret = "secret",
ResponseType = "code id_token",
Scope = "openid profile api1 offline_access",
AuthenticationMode = AuthenticationMode.Active
});
}
As recommended added the scopes but still there is a loop; the request swings between MVC4 client and IdentityServer4.
Update 4
Solved - Check my answer.

I finally got it working.
Firstly, there is a bug (Katana Bug #197) in the OWIN which makes it to handle the tokens rather 'awkwardly'. So a workaround is nuget package Kentor.OwinCookieSaver by Kentor. One will need to install at the MVC4 Client.
Thereafter, modify the client configuration as under:-
new Client
{
ClientId = "mvc4",
ClientName = "MVC 4 Web Client",
AllowedGrantTypes = {
GrantType.Hybrid,
GrantType.ClientCredentials
},
AllowAccessTokensViaBrowser = true,
RequireConsent = false,
ClientSecrets =
{
new Secret("secret".Sha256())
},
RedirectUris = { "http://localhost:53173/signin-oidc" },
PostLogoutRedirectUris = { "http://localhost:53173/signout-callback-oidc" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
},
AllowOfflineAccess = true
}
Modify the Configuration of 'Startup.cs' at MVC4 client as under
public void Configuration(IAppBuilder app)
{
app.UseKentorOwinCookieSaver();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap = new Dictionary<string, string>();
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = CookieAuthenticationDefaults.AuthenticationType
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
AuthenticationType = "oidc",
SignInAsAuthenticationType = "Cookies",
Authority = "http://localhost:5000",
RequireHttpsMetadata = false,
RedirectUri = "http://localhost:53173/signin-oidc",
ClientId = "mvc4",
ClientSecret = "secret",
ResponseType = OpenIdConnectResponseType.CodeIdTokenToken,
Scope = "openid profile api1 offline_access",
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = notification =>
{
notification.AuthenticationTicket.Identity.AddClaim(new Claim("id_token", notification.ProtocolMessage.IdToken));
notification.AuthenticationTicket.Identity.AddClaim(new Claim("access_token", notification.ProtocolMessage.AccessToken));
return Task.FromResult(0);
},
RedirectToIdentityProvider = notification =>
{
return Task.FromResult(0);
}
}
});
Rebuild Solution >> Clean and Run. Now you can use IdentityServer4 oidc for MVC4 Client.

I would recommend you review all URLs and make sure that they are all identical and there is no any extra / in Identity or client configuration.
One more thing, I can't see you scope in "Update 2".

Related

Redirect back to the ASP.NET Mvc Client after Sign-out from IdentityServer

I want to redirect back to my client after sign-out from local, then the IS4; My AspNetCore Mvc client works correctly and redirect back to the client after sign-out, but the AspNet Mvc (not Core) it doesn't.
here is my Startup.Configuration method:
public void Configuration(IAppBuilder app)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies",
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
SignInAsAuthenticationType = "Cookies",
Authority = "https://localhost:5000",
UseTokenLifetime = false,
// RedeemCode = true,
ClientId = "aspNet_client",
ClientSecret = "secret",
RedirectUri = "https://localhost:44343/sigin-oidc",
PostLogoutRedirectUri = "https://localhost:44343/signout-callback-oidc",
SaveTokens = true,
ResponseType = "code id_token",
Scope = "openid profile offline_access",
TokenValidationParameters = new TokenValidationParameters()
{
NameClaimType = JwtClaimTypes.PreferredUserName,
RoleClaimType = JwtClaimTypes.Role,
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = onAuthenticationFailed,
MessageReceived = onMessageReceived,
// AuthorizationCodeReceived = onAuthorizationCodeReceived
}
});
}
I used this method to sign-out:
public ActionResult SignOut()
{
Request.GetOwinContext().Authentication.SignOut();
return Redirect("/");
}
I used this method too:
public ActionResult SignOut()
{
System.Web.HttpContext.Current.GetOwinContext().Authentication.SignOut(
new AuthenticationProperties
{
RedirectUri = "https://localhost:44343"
},
CookieAuthenticationDefaults.AuthenticationType,
OpenIdConnectAuthenticationDefaults.AuthenticationType
);
//"Cookies", "OpenIdConnect"
}
But not worked. So my question is:
How to automatic redirect back to my AspNetMvc Client after sign-out?
This was an error reported long time ago on IdentityServer3. It got fixed here by setting IdTokenHint on logout. In this case as we use IdentityServer4, we can implement similar fix manually on ASP.NET MVC app. Here is changes need to make:
on IdentityServer project set PostLogoutRedirectUris for the client:
new Client
{
ClientId = "aspNet_client",
//All other settings ...
PostLogoutRedirectUris = { "http://localhost:44343" },
},
On ASP.NET mvc application, set OpenIdConnectAuthenticationOptions - PostLogoutRedirectUri to the same value as step 1
Change Notifications - SecurityTokenValidated and RedirectToIdentityProvider to set IdTokenHint on logout
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
// other settings...
PostLogoutRedirectUri = "http://localhost:44343",
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = n =>
{
n.AuthenticationTicket.Identity.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
return Task.FromResult(0);
},
RedirectToIdentityProvider = n =>
{
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
{
var id_token_claim = n.OwinContext.Authentication.User.Claims.FirstOrDefault(x => x.Type == "id_token");
if (id_token_claim != null)
{
n.ProtocolMessage.IdTokenHint = id_token_claim.Value;
}
}
return Task.FromResult(0);
}
}
});
If you want to redirect automatically set AccountOptions - AutomaticRedirectAfterSignOut to true on IdentityServer, default value is false.
Implemented it myself here

Why is cookie's expiration date is 'Session' when using Owin

My web application is MVC5. I'm calling an url of IdentityServer4 application to authenticate user when logging in.
Here is the method ConfigureAuth of Startup class in my application
public void ConfigureAuth(IAppBuilder app)
{
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
var authority = LayeredConfiguration.GetValue("HydraInsuranceWeb-UserManagement-Authority");
var redirectUri = LayeredConfiguration.GetValue("HydraInsuranceWeb-UserManagement-RedirectUri");
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationType = "Cookies",
SlidingExpiration = false,
ExpireTimeSpan = System.TimeSpan.FromMinutes(2),
CookieName = "MyTestCookie"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = authority,
ClientId = AuthConstants.InsuranceWebClientId,
Scope = "openid profile user.management hydra.eventhistory.api",
RedirectUri = redirectUri,
ResponseType = "code id_token",
SignInAsAuthenticationType = "Cookies",
UseTokenLifetime = false,
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = n =>
{
try
{
var transformedHydraIdentity = new HydraIdentityBuilder(n.AuthenticationTicket.Identity)
.AllowSecurityAdmin()
.IncludeRoleProfiles()
.IncludeIdToken(n.ProtocolMessage.IdToken)
.IncludeStandardClaims()
.Build();
n.AuthenticationTicket = new Microsoft.Owin.Security.AuthenticationTicket(
transformedHydraIdentity,
n.AuthenticationTicket.Properties);
}
catch (Exception ex)
{
n.HandleResponse();
n.Response.Redirect("/Error/NoAuthorization");
DiagnosticService.Writer.AddError("Authentication Error", ex);
}
return Task.FromResult(0);
},
}
});
}
After logging in, the cookie's expiration is always "Session", not the current time plus 2 minutes.
But my expectation is the cookie's expiration is a specific datetime, it should be current time plus 2 minutes. If user doesn't operate in 2 minutes, jump to the login page.
Has anyone known this issue? Please tell me how to investigate or debug to know why cookie's expiration is changed.
And there are 2 cookies: .AspNet.Cookies and MyTestCookie. Which cookie is used to authenticate user?
You need to set IsPersistent to True when signing in.
AuthenticationManager.SignIn(new AuthenticationProperties{ IsPersistent = true, ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(30)}, userIdentity);

IdentityServer3: OWIN Katana middleware is throwing "invalid_client" error as it cannot get a token

We are using IdentityServer3 as the identity provider and OWIN Katana middleware to do the handshake based on OpenId Connect. The authentication works fine as we were redirected to identity server and back to the originating website. But the issue of invalid_client appears when I try to retrieve the tokens and get claims in the "OpenIdConnectAuthenticationNotifications".
Please check the code (startup class) below and the attached screenshot.
public sealed class Startup
{
public void Configuration(IAppBuilder app)
{
string ClientUri = #"https://client.local";
string IdServBaseUri = #"https://idm.website.com/core";l
string TokenEndpoint = #"https://idm.website.com/core/connect/token";
string UserInfoEndpoint = #"https://idm.website.com/core/connect/userinfo";
string ClientId = #"WebPortalDemo";
string ClientSecret = #"aG90apW2+DbX1wVnwwLD+eu17g3vPRIg7p1OnzT14TE=";
//AntiForgeryConfig.UniqueClaimTypeIdentifier = "sub";
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = ClientId,
Authority = IdServBaseUri,
RedirectUri = ClientUri,
PostLogoutRedirectUri = ClientUri,
ResponseType = "code id_token token",
Scope = "openid profile roles",
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
},
SignInAsAuthenticationType = "Cookies",
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async n =>
{
// use the code to get the access and refresh token
var tokenClient = new TokenClient(
TokenEndpoint,
ClientId,
ClientSecret);
var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, n.RedirectUri);
if (tokenResponse.IsError)
{
throw new Exception(tokenResponse.Error);
}
// use the access token to retrieve claims from userinfo
var userInfoClient = new UserInfoClient(UserInfoEndpoint);
var userInfoResponse = await userInfoClient.GetAsync(tokenResponse.AccessToken);
// create new identity
var id = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType);
//id.AddClaims(userInfoResponse.GetClaimsIdentity().Claims);
id.AddClaims(userInfoResponse.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", n.ProtocolMessage.IdToken));
id.AddClaim(new Claim("sid", n.AuthenticationTicket.Identity.FindFirst("sid").Value));
n.AuthenticationTicket = new AuthenticationTicket(
new ClaimsIdentity(id.Claims, n.AuthenticationTicket.Identity.AuthenticationType, "name", "role"),
n.AuthenticationTicket.Properties);
},
RedirectToIdentityProvider = n =>
{
// if signing out, add the id_token_hint
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
{
var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");
if (idTokenHint != null)
{
n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
}
}
return Task.FromResult(0);
}
}
});
}
}
The client configuration at the IdSvr3 has been specified to use Hybrid Flow and I have checked that the client Id and client secret many times to verify that they are correct.
Here is the client configuration at the server side:
I was able to resolve the issue by looking at the logs generated by identity server. The logs said the client secret is incorrect, when I have checked several times that the secret was exact to what was showing on the identity server. But then I realised that the secret should be the actual text and NOT the hashed one. The modified code that worked is below:
string ClientId = #"WebPortalDemo";
//string ClientSecret = #"aG90apW2+DbX1wVnwwLD+eu17g3vPRIg7p1OnzT14TE="; // Incorrect secret, didn't work
string ClientSecret = #"love"; // Actual text entered as secret, worked
Credit: #rawel

IdentityServer3 using LinkedIn as external login

Trying to use LinkedIn as an external login but I keep having this error. After authorization screen. It goes to /callback instead of the initial application.
There is an error determining which application you are signing into.
Return to the application and try again.
Here's my configuration
private void ConfigureIdentityProviders(IAppBuilder app, string signInAsType)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseLinkedInAuthentication(new LinkedInAuthenticationOptions()
{
ClientId = "[...]",
ClientSecret = "[...]"
});
}
I'm not really sure how to configure the client either. I know we need the flow.Authorization code. But beyond that I'm lost.
new Client
{
ClientId = "[...]",
ClientName = "Linkedin Client",
Enabled = true,
Flow = Flows.AuthorizationCode,
RedirectUris =
new List<string> {_baseUrl, "http://localhost/mtthelloworld"},
PostLogoutRedirectUris =
new List<string> {_baseUrl},
ClientSecrets = new List<Secret>()
{
new Secret("[???]".Sha256())
},
}
Edit added ConfigureIdentityServerConfig:
private void ConfigureIdentityServer(IAppBuilder appBuilder)
{
var idsFactory = new IdentityServerServiceFactory()
.UseInMemoryClients(Clients.Get())
.UseInMemoryScopes(Scopes.Get());
idsFactory.UserService = new Registration<IUserService>(typeof(UserService));
var idsOptions = new IdentityServerOptions()
{
SiteName = "SSO",
SigningCertificate = VcCert.Load("CN=cert.local"),
Factory = idsFactory,
RequireSsl = false,
LoggingOptions = new LoggingOptions()
{
EnableWebApiDiagnostics = true,
EnableHttpLogging = true,
EnableKatanaLogging = true,
WebApiDiagnosticsIsVerbose = true
},
PluginConfiguration = ConfigureWsFederation,
AuthenticationOptions = new AuthenticationOptions()
{
IdentityProviders = ConfigureIdentityProviders
}
};
appBuilder.Map("/identity", idApp => { idApp.UseIdentityServer(idsOptions); });
appBuilder.UseIdentityServer(idsOptions);
}
First of all you have to obtain client id and client secret from LinkedIn. This is usually done by registering your application on the external provider side - LinkedIn.
Note that, when you are delegating authentication to external provider, then your server is a client and LinkedIn is a server.
Regarding the configuration method for external providers, do not call CookieAuthenticationMiddleware inside this method. Instead configure only the LinkedIn authentication middleware.
private void ConfigureIdentityProviders(IAppBuilder app, string signInAsType)
{
app.UseLinkedInAuthentication(new LinkedInAuthenticationOptions()
{
AuthenticationType = "LinkedIn",
SignInAsAuthenticationType = signInAsType,
ClientId = "[...]", // client id you've obtained from LinkedIn
ClientSecret = "[...]", // client secret you've obtained from LinkedIn
});
}
You don't need to create new Client as you're doing it in your second code snippet. These classes are for meant for clients of your application, and as I've said earlier in this case your application is the client.
EDIT
You do not need to configure CookieAuthenticationMiddleware in the server where you host IdentityServer3 - let's call this server an identity provider.
public void Configuration(IAppBuilder app)
{
app.UseIdentityServer(new IdentityServerOptions
{
// ...
AuthenticationOptions = new AuthenticationOptions
{
IdentityProviders = (IAppBuilder builder, string signInAsType) =>
{
builder.UseLinkedInAuthentication(new LinkedInAuthenticationOptions
{
AuthenticationType = "LinkedIn",
SignInAsAuthenticationType = signInAsType,
ClientId = "[...]",
ClientSecret = "[...]"
};
}
}
});
}
The question that you could ask is - well, then where do I need to use it? The answer is simple - use it in clients that are delegating authorization to your identity provider.
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
SignInAsAuthenticationType = "Cookies",
// ...
});
}

Identity server 3 client with mvc and api not refreshing access token

I have a working identity provider. The client I have designed to authenticate against it is a single project combining MVC and web API. The initial authentication is done me the MVC. If the access token becomes invalid it refreshes as expected.
MVC side:
public partial class Startup {
public void ConfigureAuth(IAppBuilder app)
{
//AntiForgeryConfig.UniqueClaimTypeIdentifier = "sub";
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies",
CookieName = "CookieName",
ReturnUrlParameter = "/Dashboard",
LogoutPath = new PathString("/"),
});
app.UseOpenIdConnectAuthentication(GetOpenIdConnectAuthenticationOptions());
}
private OpenIdConnectAuthenticationOptions GetOpenIdConnectAuthenticationOptions()
{
var options = new OpenIdConnectAuthenticationOptions
{
ClientId = "client.id",
Authority = AuthorityUrl,
RedirectUri = RedirectUri,
PostLogoutRedirectUri = RedirectUri,
ResponseType = "code id_token",
Scope = "openid profile email offline_access roles company utc_offset service_api",
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
},
SignInAsAuthenticationType = "Cookies",
Notifications = GetOpenIdConnectAuthenticationNotifications()
};
return options;
}
private OpenIdConnectAuthenticationNotifications GetOpenIdConnectAuthenticationNotifications()
{
var container = UnityLazyInit.Container;
var authorizationProvider = container.Resolve<AuthorizationProvider>();
var notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async n =>
{
authorizationProvider.Authority = Authority;
authorizationProvider.LoginMethod = LoginMethod;
var tokenResponse = await authorizationProvider.GetAccessAndRefreshTokens(n);
var userInfoClaims = await authorizationProvider.GetUserInfoClaims(tokenResponse);
userInfoClaims = authorizationProvider.TransformUserInfoClaims(userInfoClaims);
// create new identity
var id = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType);
id.AddClaims(userInfoClaims);
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", n.ProtocolMessage.IdToken));
id.AddClaim(new Claim("sid", n.AuthenticationTicket.Identity.FindFirst("sid").Value));
var user = authorizationProvider.GetUser(id);
var applicationClaims = authorizationProvider.GetApplicationClaims(user);
id.AddClaims(applicationClaims);
var permisionClaims = authorizationProvider.GetPermisionClaims(user);
id.AddClaims(permisionClaims);
n.AuthenticationTicket = new AuthenticationTicket(
new ClaimsIdentity(id.Claims, n.AuthenticationTicket.Identity.AuthenticationType, "name", "role"),
n.AuthenticationTicket.Properties);
},
RedirectToIdentityProvider = n =>
{
// if signing out, add the id_token_hint
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
{
var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");
if (idTokenHint != null)
{
n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
}
}
return Task.FromResult(0);
}
};
return notifications;
}
}
The presentation layer (browser side) leverages angulerjs however I have not incorporated any support for authentication. I am relying on the MVC.
When you presentation layer makes calls to the API it automatically validates against the access token retrieved by the MVC but if it expires it is unable to refresh the access token. It also doesn’t return unauthorized. It appears to be trying to refresh but fails. The presentation receives the HTML for the error page of the identity provider when the api calls attempt to refresh the token.
How do I fix this? It seems to me is supposed to authenticate and refresh automatically for the MVC and the API when they are combined but this is not working for me.
note to clarify the start up configuration above is shared but the MVC and the API.
new Client
{
ClientName = "MVC Client",
ClientId = "client.id",
ClientSecrets = new List<Secret> {
new Secret("secret".Sha256())
},
Flow = Flows.Hybrid,
AllowedScopes = new List<string>
{
Constants.StandardScopes.OpenId,
Constants.StandardScopes.Profile,
Constants.StandardScopes.Email,
Constants.StandardScopes.OfflineAccess,
"roles",
"company",
"utc_offset",
"service_api
"
},
RequireConsent = false,
RedirectUris = new List<string>
{
REMOVED
},
PostLogoutRedirectUris = new List<string>
{
REMOVED
},
AllowedCorsOrigins = new List<string>
{
REMOVED
},
AccessTokenLifetime = 60,
IdentityTokenLifetime = 60,
AbsoluteRefreshTokenLifetime = 60 * 60 * 24,
SlidingRefreshTokenLifetime = 60 * 15,
},
#brockallen - The short of this is. I have an application that is MVC and WEBAPI and Anjulgarjs. I do not think a hybrid like this is wise but I inherited this application and now I have to find a way to make it work with Idnetity Server 3.
I would be grateful for any guidance. Please.
I was having the same issue as you. The problem is that you are setting a cookie for MVC, but you are not setting the expiration date, thus MVC does not know that the cookie has expired. What you need to do is set the expiration date for the AuthenticationTicket in the following way:
n.AuthenticationTicket.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddSeconds(int.Parse(n.ProtocolMessage.ExpiresIn));
n.AuthenticationTicket.Properties.IssuedUtc = DateTime.Now;
//Add encrypted MVC auth cookie
n.AuthenticationTicket = new AuthenticationTicket(
nid,
n.AuthenticationTicket.Properties);
I've also set the issued date, but that's not mandatory

Resources