Identity Server 4 Silent Renew ErrorResponse: login_required - identityserver4

I have cloned the repo from the redux-oidc-example and it works for the most part but after a few hours it gives the following error:
Action payload: ErrorResponse: login_required
at new e (oidc-client.min.js:1)
at t [as _processSigninParams] (oidc-client.min.js:1)
at t [as validateSigninResponse] (oidc-client.min.js:1)
at oidc-client.min.js:1
UserManager.js looks like this:
const userManagerConfig = {
client_id: 'js.dev',
client_secret: 'secret',
redirect_uri: `${window.location.protocol}//${window.location.hostname}${window.location.port ? `:${window.location.port}` : ''}/callback`,
response_type: 'id_token token',
scope: 'openid email profile role offline_access',
authority: 'http://localhost:8080',
silent_redirect_uri: `${window.location.protocol}//${window.location.hostname}${window.location.port ? `:${window.location.port}` : ''}/silent_renew.html`,
automaticSilentRenew: true,
filterProtocolClaims: true,
loadUserInfo: true
};
and my identity server config:
{
"Enabled": true,
"ClientId": "js.dev",
"ClientName": "Javascript Client",
"ClientSecrets": [ { "Value": "K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=" } ],
"AllowedGrantTypes": [ "implicit", "authorization_code" ],
"AllowedScopes": [ "openid", "email", "profile", "role", "offline_access" ],
"AllowOfflineAccess": true,
"AllowAccessTokensViaBrowser":true,
"RedirectUris": [
"http://localhost:8081/callback",
"http://localhost:8081/silent_renew.html"
],
"PostLogoutRedirectUris": [
"http://localhost:8081"
],
"AccessTokenLifetime": 900,
"RequireConsent": false
}
I noticed that prior to error last valid response had one cookie response(idsrv.session) with empty value with the expiry date set to the previous year:
I believe this to be the root cause of the issue, I searched it on related Github repo and tried to add the Cookie.SameSite to none but it didn't help:
services.AddAuthentication()
.AddSaml(Configuration,externalProviders.UseSaml)
.AddCookie(options => {
options.SlidingExpiration = true;
options.ExpireTimeSpan = TimeSpan.FromDays(30);
options.Cookie.SameSite = SameSiteMode.None;
});
Any idea!

This is likely due to your IDP session expiring - if you call the authorize endpoint with prompt=none but it's unable to satisfy that request because no valid session exists (i.e. authentication cookie does not exist or has expired) then it will return error=login_required.
If this occurs then the correct course of action is to do an interactive (i.e. prompt=login) sign in request in the top level browser window.

After searching the Identity Server 4 repo, I made the following changes to my code:
services.AddIdentityServer(options=>
{
options.Authentication.CookieLifetime = TimeSpan.FromDays(30);
options.Authentication.CookieSlidingExpiration = true;
})
.AddProfileService<ProfileService>()
.AddSigningCertificate(Configuration)
.AddInMemoryClients(Configuration.GetSection("IdentityServer:Clients"))
.AddInMemoryIdentityResources(Resources.GetIdentityResources());
It started working afterward, but you would have to login again after you close the browser or reopen a new tab I guess it's because of the sessionStorage.

When the session expires the signin-callback is being called by STS having a query parameter called 'error' with the value 'login_required'.
In the signin-callback, before completing sign-in, you can check for this query parameter and if it's found you can sign-out also from your web client.

I had the same issue and tried the proposed above, but for me, it actually was SameSiteMode not set correctly on IdentityServer Cookies. It caused Callback error: ErrorResponse: login_required right after login and after N attempts user was logged out.
This helped me https://github.com/IdentityServer/IdentityServer4/blob/main/src/IdentityServer4/host/Extensions/SameSiteHandlingExtensions.cs
What they do is based on this article https://devblogs.microsoft.com/dotnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/
Hope this is useful.
Update.
I had another issue related to this when the user was logged out after re-opening a browser (especially on Android Chrome). login_required error was shown. I noticed that session cookie Expires/Max-Age was set to Session and not some future date. Probably because of that check session iframe (with src={identity server url}/connect/checksession) failed as Identity Server thought there was no session as cookie expired.
I tried setting cookie lifetime via options, but it didn't work as expected for some reason. Lifetime was always 14 days:
services.AddIdentityServer(options=>
options.Authentication.CookieLifetime = TimeSpan.FromDays(30);
options.Authentication.CookieSlidingExpiration = true;
})
Then I tried this and it worked for me:
services.ConfigureApplicationCookie(options => {
options.ExpireTimeSpan = sessionCookieLifetime;
options.SlidingExpiration = true;
})

Related

AWS Cognito "invalid_state" error with federated identities

I'm using AWS cognito as a federated identity service to federate Salesforce IDP (we'll have more in the future)
Recently I started getting an "invalid state" error. And after days of research, I found out that:
when the authentication flow starts on cognito there is no error
cognito redirects the user to salesforce
user gets sent back to cognito after login
when the authentication flow starts on salesforce we receive the "invalid_state" error.
user logs in directly over salesforce
salesforce redirects the user to cognito
I need to be able to start the flow from salesforce for the following cases:
the first time user is registered in salesforce
when user reset's password in salesforce
The setup of AWS Cognito via CDK:
const userPool = new UserPool(this, 'duck-user-pool', {
autoVerify: {
email: true,
phone: false,
},
mfa: Mfa.OFF,
mfaSecondFactor: {
sms: false,
otp: false,
},
selfSignUpEnabled: false,
standardAttributes: {
email: {
mutable: true,
required: true,
},
}
});
const salesforceIdP = new CfnUserPoolIdentityProvider(
this,
'salesforceIdP',
{
attributeMapping: {
email: 'email',
family_name: 'family_name',
given_name: 'given_name',
},
providerDetails: {
attributes_request_method: 'GET',
authorize_scopes: 'email openid profile',
oidc_issuer: config.SalesforceBaseUrl,
client_id:
salesforceIdPCredentials.secretValueFromJson(
'CLIENT_ID'
),
client_secret:
salesforceIdPCredentials.secretValueFromJson(
'CLIENT_SECRET'
),
},
providerName: 'salesforce-idp',
providerType: 'OIDC',
userPoolId: userPool.userPoolId,
}
);
const spaClient = userPool.addClient(
'duck-user-pool-client-spa',
{
authFlows: {
userPassword: true,
userSrp: true,
},
generateSecret: false,
refreshTokenValidity: Duration.days(30),
supportedIdentityProviders: [
UserPoolClientIdentityProvider.COGNITO,
UserPoolClientIdentityProvider.custom(
salesforceIdP.providerName
),
],
oAuth: {
callbackUrls: config.CallbackURLs,
flows: {
authorizationCodeGrant: true,
implicitCodeGrant: false,
clientCredentials: false,
},
logoutUrls: config.LogoutURLs,
scopes: [
OAuthScope.EMAIL,
OAuthScope.OPENID,
OAuthScope.PHONE,
OAuthScope.PROFILE,
],
},
}
);
On the salesforce side, configuration was made to redirect the user to following url:
https://sandbox-duck.auth.eu-west-1.amazoncognito.com/oauth2/idpresponse
I've found out cognito is using a query parameter called state (against CSRF attacks) and if the parameter is not in the URL it throws this error.
The setup was working until a month ago but suddenly it stopped working. Is there a way to work around this limitation?

Unable to configure ASP.NET for Azure Access Token

I was hoping that someone might be able to shed some light on issues that I'm having with authentication. I've mostly used this guidance: https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-spa-overview
I've got a react app that is successfully (I think...) retrieving access tokens for my API:
const account = msalInstance.getActiveAccount();
if (account) {
msalInstance.acquireTokenSilent({
...apiToken,
account: account
}).then((response) => {
setToken(response.accessToken);
});
}
My requests place the token in the authorization header:
Headers
My token looks looks like: Token
API Registration
My API returns 401 whenever I use the Authorize attribute. Because my client is retrieving a token that looks correct, I'm assuming the issue is on my API. This is what I have in my startup auth:
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
AccessTokenFormat = new JwtFormat(
new TokenValidationParameters
{
// Check if the audience is intended to be this application
ValidAudiences = new[] { [MY_API_CLIENT_ID (SAME AS AUDIENCE IN TOKEN)], [MY API REGISTRATION URI] },
// Change below to 'true' if you want this Web API to accept tokens issued to one Azure AD tenant only (single-tenant)
// Note that this is a simplification for the quickstart here. You should validate the issuer. For details,
// see https://github.com/Azure-Samples/active-directory-dotnet-native-aspnetcore
ValidateIssuer = false,
ValidateAudience = false,
ValidateTokenReplay = false,
ValidateIssuerSigningKey = false,
ValidateLifetime = false,
ValidateActor = false, //all false for testing
},
new OpenIdConnectSecurityKeyProvider("https://login.microsoftonline.com/[MY_TENANT_ID]/v2.0/.well-known/openid-configuration")
),
});
Tough silent error here. I noticed that none of the validation callbacks were being invoked. I was missing the package Microsoft.Owin.Host.SystemWeb

Add OneLogin as an OIDC to IdentityServer4

I am currently setting up IdentityServer4 with ASP.NET Core Identity, and I am trying to integrate this with OneLogin OIDC.
I have my IdentityServer4 service setup and running. I have added the Google scheme to this, so on my IdentityServer login page I have a login form and the Google login button.
I have created several client applications, an MVC app, a basic javascript app and also an Angular app.
With these clients I am able to authenticate against IdentityServer and get an access token, and then access a .NET Core WebAPI I have setup as an API scope.
My company uses OneLogin as our SSO, so I am trying to see if I can link IdentityServer to OneLogin.
In my IdentityServer Startup.cs ConfigureService method I have added the following
services.AddAuthentication()
.AddGoogle(options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.ClientId = "clientid";
options.ClientSecret = "secret";
})
.AddOpenIdConnect("oidc", "OneLogin", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.SignOutScheme = IdentityServerConstants.SignoutScheme;
options.SaveTokens = true;
options.Authority = "https://companyname.onelogin.com/oidc/2";
options.ClientId = "clientid";
options.ClientSecret = "secret";
options.ResponseType = "code";
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
};
});
I am able to view the following Provider Configuration from OneLogin for my corporate domain:
{
"acr_values_supported": ["onelogin:nist:level:1:re-auth"],
"authorization_endpoint": "https://companyname.onelogin.com/oidc/2/auth",
"claims_parameter_supported": true,
"claims_supported": ["sub", "email", "preferred_username", "name", "updated_at", "given_name", "family_name", "locale", "groups", "params", "phone_number", "acr", "sid", "auth_time", "iss"],
"grant_types_supported": ["authorization_code", "implicit", "refresh_token", "client_credentials", "password"],
"id_token_signing_alg_values_supported": ["HS256", "RS256", "PS256"],
"issuer": "https://companyname.onelogin.com/oidc/2",
"jwks_uri": "https://companyname.onelogin.com/oidc/2/certs",
"request_parameter_supported": false,
"request_uri_parameter_supported": false,
"response_modes_supported": ["form_post", "fragment", "query"],
"response_types_supported": ["code", "id_token token", "id_token"],
"scopes_supported": ["openid", "name", "profile", "groups", "email", "params", "phone"],
"subject_types_supported": ["public"],
"token_endpoint": "https://companyname.onelogin.com/oidc/2/token",
"token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "none"],
"userinfo_endpoint": "https://companyname.onelogin.com/oidc/2/me",
"userinfo_signing_alg_values_supported": ["HS256", "RS256", "PS256"],
"code_challenge_methods_supported": ["S256"],
"introspection_endpoint": "https://companyname.onelogin.com/oidc/2/token/introspection",
"introspection_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "none"],
"revocation_endpoint": "https://companyname.onelogin.com/oidc/2/token/revocation",
"revocation_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "none"],
"claim_types_supported": ["normal"]
}
I have a OneLogin developer account, and in there I have created a "OpenId Connect (OIDC)" application. Here I have the options to configure a Login URL and a Redirect URL.
I put the redirect URL as https://localhost:44361/signin-oidc, where localhost:44361 is my IdentityServer instance. I Initially put localhost:4200/login as the login URL, which is the URL of my angular application.
When I navigate to my Angular app, I am directed to my IdentityServer login page as expected. Here I have a button for "One Login". I click this button, which does then take me to OneLogin, again as expected. I enter my login credentials. OneLogin then redirects me to https://localhost:44361/signin-oidc. However, I receive the following error message:
An unhandled exception occurred while processing the request.
OpenIdConnectProtocolException: Message contains error: 'invalid_client', error_description: 'client authentication failed', error_uri: 'error_uri is null'.
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.RedeemAuthorizationCodeAsync(OpenIdConnectMessage tokenEndpointRequest)
Exception: An error was encountered while handling the remote login.
Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler<TOptions>.HandleRequestAsync()
Can anyone help me understand what I am missing? The OneLogin documentation doesn't seem to be very clear (no on screen help or tips when setting up the OIDC app).
I can't find any tutorials or documentation on IdentityServer4 and OneLogin, so I am wondering if what I want to achieve is even possible?
Sods Law.
I managed to find a solution in this OneLogin blog post, 20 minutes after I posted my question.
https://www.onelogin.com/blog/how-to-use-openid-connect-authentication-with-dotnet-core
The step I was missing was creating a Custom Connector before creating my OIDC Application in OneLogin.
With that connector in place, I am able to authenticate and I am returned to my Angular SPA.

JS Report Server Console error: Authorization server has no "username" field in its response, token assumed as invalid

My js report server with client ui applications was working with username filed by adding one claim e.g. Claim('username', 'user name value') in identityserver.
4 version 1.1. B ut recently client has upgraded the identityserver 4 version to 2.2.0 and netcoreapp2.1 .
Now the client ui applications get "Unauthorized" error. When I run the application locally I see one error in jsreport server console:
error: Authorization server has no "username" field in its response, token assumed as invalid.
I have tried to find solution in the sample:
https://github.com/bjrmatos/jsreport-with-authorization-server-sample but they have not upgraded the sample for latest .net core and identity server yet, I see the node js sample link "https://github.com/IdentityServer/IdentityServer4.Samples/tree/release/NodeJsApi" does not exists. so I am unable to solve the issue. Can anyone help me please on this?
Thanks in advance.
I have found solution to solve this error by adding a claim type with user name and declare that in api resource scope:
new ApiResource
{
Name="jsreportscope",
DisplayName = "JavaScript based reporting platform",
Scopes=
{
new Scope()
{
Name="jsreportscope",
UserClaims = new List<string>(){"username" }
}
},
UserClaims = new List<string>(){"username"},
ApiSecrets = { new Secret("yoursecret".Sha256()) },
}
But now it goes to the previous problem that I fixed by adding a claim type matching the value of username field value with identity server 1.1 version but now we have upgraded the identity server version to 2.1 and again getting the error. The it was able to authorize any user of identity server for report access. Here is the jsreport.config.js code I am using:
{
"store": { "provider": "fs" },
"httpPort": 5004,
"allowLocalFilesAccess": true,
"extensions": {
"authentication": {
"cookieSession": {
"secret": "<your strong secret>"
},
"admin": {
"username": "IdentityServer4User#domain.com",
"password": "Password"
},
"authorizationServer": {
"tokenValidation": {
"endpoint": "http://localhost:5000/connect/introspect",
"usernameField": "username",
"activeField": "active",
"scope": {
"valid": ["jsreportscope"]
},
"auth": {
"type": "basic",
"basic": {
"clientId": "jsreport",
"clientSecret": "yoursecret"
}
}
}
},
"enabled": true
},
"authorization": {
"enabled": true
},
"sample-template": {
"createSamples": true
}
}
}
But now I can login and access reports from report server if login by only the user IdentityServer4User#domain.com any other users is getting unauthorized error. In the report server console the error is shown like:
error: username "OtherIdentityServer4User#domain.com" returned from authorization server is not a jsreport user. I don not want to add all the identity server users to js report server.

Problems with Azure application manifest trying to authenticate with office-js-helpers in an Outlook web add-in

I'm using office-js-helpers in order to get an OAuth token in my Outlook web add-in so I can use it for OAuthCredentials with the EWS Managed API (code for that is in an Azure App Service using the ASP.NET Web API).
I have configured my app's application registration in my test Office 365 tenant (e.g. mytenant.onmicrosoft.com, which is NOT the same Azure subscription hosting the web app - if that matters) as a Native app with oauth2AllowImplicitFlow set to true. I used a Native app type instead of a Web/API app to bypass an unexpected error indicating my app requires admin consent - even though no application permissions were requested - but that's another story (perhaps I must use Native anyway - not 100% sure).
I made sure that the Redirect URI (aka reply URL) in the app registration points to the same page as the Outlook add-in (e.g. https://mywebapp.azurewebsites.net/MessageRead.html).
Here is my app manifest:
{
"appId": "a11aaa11-1a5c-484a-b1d6-86c298e8f250",
"appRoles": [],
"availableToOtherTenants": true,
"displayName": "My App",
"errorUrl": null,
"groupMembershipClaims": null,
"optionalClaims": null,
"acceptMappedClaims": null,
"homepage": "https://myapp.azurewebsites.net/MessageRead.html",
"identifierUris": [],
"keyCredentials": [],
"knownClientApplications": [],
"logoutUrl": null,
"oauth2AllowImplicitFlow": true,
"oauth2AllowUrlPathMatching": false,
"oauth2Permissions": [],
"oauth2RequiredPostResponse": false,
"objectId": "a11aaa11-99a1-4044-a950-937b484deb8e",
"passwordCredentials": [],
"publicClient": true,
"supportsConvergence": null,
"replyUrls": [
"https://myapp.azurewebsites.net/MessageRead.html"
],
"requiredResourceAccess": [
{
"resourceAppId": "00000003-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d",
"type": "Scope"
}
]
},
{
"resourceAppId": "00000002-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "311a71cc-e848-46a1-bdf8-97ff7156d8e6",
"type": "Scope"
},
{
"id": "a42657d6-7f20-40e3-b6f0-cee03008a62a",
"type": "Scope"
}
]
},
{
"resourceAppId": "00000002-0000-0ff1-ce00-000000000000",
"resourceAccess": [
{
"id": "2e83d72d-8895-4b66-9eea-abb43449ab8b",
"type": "Scope"
},
{
"id": "ab4f2b77-0b06-4fc1-a9de-02113fc2ab7c",
"type": "Scope"
},
{
"id": "5eb43c10-865a-4259-960a-83946678f8dd",
"type": "Scope"
},
{
"id": "3b5f3d61-589b-4a3c-a359-5dd4b5ee5bd5",
"type": "Scope"
}
]
}
],
"samlMetadataUrl": null
}
I also made sure to add the authority URLs to my add-in's manifest:
<AppDomains>
<AppDomain>https://login.windows.net</AppDomain>
<AppDomain>https://login.microsoftonline.com</AppDomain>
</AppDomains>
This is the code I'm using in the add-in for the authentication with office-js-helpers:
// The Office initialize function must be run each time a new page is loaded.
Office.initialize = function(reason) {
$(document).ready(function () {
// Determine if we are running inside of an authentication dialog
// If so then just terminate the running function
if (OfficeHelpers.Authenticator.isAuthDialog()) {
// Adding code here isn't guaranteed to run as we need to close the dialog
// Currently we have no realistic way of determining when the dialog is completely
// closed.
return;
}
// Create a new instance of Authenticator
var authenticator = new OfficeHelpers.Authenticator();
authenticator.endpoints.registerAzureADAuth('a11aaa11-1a5c-484a-b1d6-86c298e8f250', 'mytenant.onmicrosoft.com');
// Add event handler to the button
$('#login').click(function () {
$('#token', window.parent.document).text('Authenticating...');
authenticator.authenticate('AzureAD', true)
.then(function (token) {
// Consume and store the acess token
$('#token', window.parent.document).text(prettify(token));
authToken = token.access_token;
})
.catch(function (error) {
// Handle the error
$('#token', window.parent.document).text(prettify(error));
});
});
});
};
Now the code in the add-in can properly sign in the user and ask for the required permissions, but after clicking the Accept button on the application authorization step the following error is returned:
AADSTS50011: The reply address 'https://mywebapp.azurewebsites.net' does not match the reply addresses configured for the application: 'a11aaa11-1a5c-484a-b1d6-86c298e8f250'. More details: not specified
The error now returns every time I click the Login button (the user is no longer prompted to sign in). It never did retrieve the token. The full auth URL is:
https://login.windows.net/mydomain.onmicrosoft.com/oauth2/authorize?response_type=token&client_id=a11aaa11-484a-b1d6-86c298e8f250&redirect_uri=https%3A%2F%2Fmywebapp.azurewebsites.net&resource=https%3A%2F%2Fgraph.microsoft.com&state=982599964&nonce=3994725115
What am I doing wrong? Could the issue actually be because the host name of the web app (the redirect URI) does not match the domain of the Azure AD tenant hosting the app registration? If so, how can I grant permissions to Exchange Online from my Azure subscription hosting the web app which does not have Office 365 or Exchange Online? Would I have to add an Azure subscription to my test Office 365 tenant so that it can also host a web application??
From your app manifest, I found that you used https://myapp.azurewebsites.net/MessageRead.html as one of the replyUrls.
And below is the url that you are using to get consent from user.
https://login.windows.net/mydomain.onmicrosoft.com/oauth2/authorize?response_type=token&client_id=a11aaa11-484a-b1d6-86c298e8f250&redirect_uri=https%3A%2F%2Fmywebapp.azurewebsites.net&resource=https%3A%2F%2Fgraph.microsoft.com&state=982599964&nonce=3994725115.
If you observe above url, you mentioned redirect_uri as https://myapp.azurewebsites.net. But redirect_uri should match with at least one of the replyUrls you mentioned in the app manifest.
Try to replace https://myapp.azurewebsites.net with https://myapp.azurewebsites.net/MessageRead.html in authorization url.
I have updated them in below url, if you want you can directly try below url.
https://login.windows.net/mydomain.onmicrosoft.com/oauth2/authorize?response_type=token&client_id=a11aaa11-484a-b1d6-86c298e8f250&redirect_uri=https%3A%2F%2Fmywebapp.azurewebsites.net%2FMessageRead.html&resource=https%3A%2F%2Fgraph.microsoft.com&state=982599964&nonce=3994725115

Resources