Silent authentification with oauth2 (prompt=none) - authentication

Hi I have SPA(Single page application) where I use oauth2 implicit grant for authorization. As Identity server I have Wso2 identity server 5.4.1.
I am able to authorize the app and everything works as desired - also I configured to skip the consent.
Here goes the problem:
I am trying to silently reauthenticate logged user with following link with help of .../oauth2/authorize service and attribute prompt=none:
https://xxx:9447/oauth2/authorize?response_type=id_token token&nonce=123&prompt=none&client_id=xxxx&scope=openid&redirect_uri=http://localhost:63342/myapp/www/index.html&id_token_hint=previous_user_token
With promp=none as written here:
http://openid.net/specs/openid-connect-core-1_0.html#AuthorizationEndpoint
I should be able to authenticate user when he is logged and the consent is configured to be skipped or always approve.
But I always get the same error back in URI:
http://localhost:63342/myapp/www/index.html#error_description=Authentication+required&error=login_required&session_state=state124124125125.1251512

This error login_required means that your user is not logged in on the IP. You must first ask him to connect by redirecting it to the authorization endpoint without the prompt parameter set to none.
See : http://openid.net/specs/openid-connect-core-1_0.html#AuthError
login_required
The Authorization Server requires End-User authentication. This error MAY be returned when the prompt parameter value in the Authentication Request is none, but the Authentication Request cannot be completed without displaying a user interface for End-User authentication.
According to the documentation, it seems that the user must choose the option on the consent page: Approve Always. Have you tested with this option?
Docs: https://docs.wso2.com/display/IS530/Basic+Client+Profile+with+Playground
Click Approve to provide consent to this action. The screen mentions
the service provider by name and requests for user consent to provide
user information to that particular service provider. The user can
either Deny to provide information to the service provider. Approve
to provide user profile information to this service provider only for
this time.
Approve Always to provide approval to share user profile
information with the service provider even in the future without
prompting for consent again.

Related

IdentityServer4 - Login via ADFS without logon prompt appearing

With the use of IdentityServer4 and the OIDC protocol, I've managed to get my SPA and my .net core web api authenticating against a sql server user store, as well as ADFS which is great. However, when the user first clicks the 'Continue with ADFS' button, the login prompt is shown asking the user for their credentials. My understanding was that with the use of openId connect and IdentityServer, we could add external identity providers such as ADFS to our IdentityServer application and if ADFS is chosen for login with the user already logged in to ADFS via their local machine, then the authentication would happen seamlessly without the need to input windows user credentials again. There are other steps in order to achieve this of course, like linking the ADFS UserId with our SQL Database User Id table, but overall my understanding was that this would be entirely possible.
After a user logs out from an ADFS login, the next time the user chooses to log back in with ADFS, the 'Challenge' method that is run within my IdentityServer application to initiate the redirect to ADFS often recognises that the user has already logged in recently and therefore just logs them right in without the need for their credentials again.
My question is - is it actually possible to avoid the initial login prompt altogether? Or will the browser insist that credentials are provided if the user hasn't logged into the application for a while?
It certainly is possible but it may involve specific browser config in ADFS and also may require your IDP to be in the intranet zone in Windows Internet settings.
Check out these articles:
https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/operations/configure-intranet-forms-based-authentication-for-devices-that-do-not-support-wia
https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/operations/configure-ad-fs-browser-wia

OpenID Connect, redirect without login form if not already logged in?

In OpenID Connect, I would like my users to be automatically connected to my client if they are connected to the identity provider (given that they already authorized my client app).
Here is the workflow I want :
USER arrives on CLIENT homepage
USER is redirected to IdP (Authorization request)
If he's logged in IdP, he's redirected to CLIENT and OIDC workflow begins, then he's logged in CLIENT
If he's not logged in IdP or he did not authorize CLIENT to access his identity, the login form of IdP is NOT displayed to USER and he's redirected to CLIENT homepage, not logged in
It would be like "Gateway" mode in CAS.
I use Authorization Code Flow and I don't want to use Javascript with Implicit Flow to login through JS dynamically.
Do you know if it is possible ? I can not find it in the spec.
Thanks :)
You are considering SSO behaviour on-top of IDP. This is usually outside OpenID Connect specification and usually bound to specific identity provider you are using (ex:- Azure, PING or WSO2). But there are some parameters to tweak the this behaviour such as prompt and login_hint which are optional.
From OpenID Connect authentication request section
prompt
Space delimited, case sensitive list of ASCII string values that
specifies whether the Authorization Server prompts the End-User for
reauthentication and consent.
Valid values are login, none, consent and select_account. You can use them to enforce force login or to allow a select account.
login_hint
Hint to the Authorization Server about the login
identifier the End-User might use to log in (if necessary)
One good example is enabling SSO behaviour by passing login_hint to identity provider. If identity provider can verify identity against (for example) a corporate LDAP and detect logged in state, you can give credential free login experience. At the same time, you may use prompt=login to enforce a login, even when identity provider hold a logged in session.
Alternatively, you can use signinSilent(). I have used it on my login page ngOnInit (since AuthGuard will anyway redirect the user to login, I thought it will be the perfect place in my scenario).
// login.ts
ngOnInit(): void {
this.authService.signinSilent().then(_ => {}).catch(_ => {});
}
// authService
public signinSilent() {
return this.userManager.signinSilent();
}
signinSilent method will return the user object if user already has a valid session with idp. else it will throw an error, probably login_required.

How do I keep the user logged-in with Implicit flow?

From what I understand, the end-result of the implicit flow is the access token, which allows the client (in my case a JS SPA) to authenticate into resource servers (APIs).
The access token is usually only valid for ~1 hour, then it expires - making it useless.
What should my JS app do then? Redirecting the user back to the auth server is unrealistic since then the user will have to reenter their credentials every 1 hour!
I also know that the implicit flow doesn't support refresh tokens so I can't use those either.
Is there a way to persist the user's login? How do things like Facebook keep you logged-in indefinitely?
Just to clarify, you are asking about the Implicit flow which is detailed in the OAuth 2.0 RFC rather than OpenID Connect which deals more with authentication of a user?
With the implicit flow you do have to regularly call the authorisation endpoint to obtain a new token, but if the user remains logged into their identity provider then they should not be prompted to resubmit their credentials, and the token will be returned as a hash fragment in the redirect uri, with no user interaction required.
You can use an AJAX call to get the token on a back-channel so your SPA app user experience is not affected by the need to get new tokens.
To address the points you highlight in your question:
The access token is usually only valid for ~1 hour, then it expires -
making it useless.
Correct!
then the user will have to reenter their credentials every 1 hour!
Not necessarily.
If the user stays logged into the identity provider (e.g. facebook, google) then there will be a browser cookie between the user and that provider. This effectively means the identity provider does not need the user to re-enter credentials. The authorisation server should be able to return you a token with no interaction required.
Is there a way to persist the user's login?
You can't control it from your SPA. It's totally dependent on the user staying logged onto the identity provider. If they stay logged into facebook, google (or whatever IDP you app uses) then you should be able to get tokens non-interactively.
This article nicely explains how the implicit flow can be implemented.
If the session at the OP is still active (via a cookie perhaps), then OpenID Connect has a mechanism to refresh tokens in a (hidden) iframe: prompt=none.
According to the spec, when sending this flow...
The Authorization Server MUST NOT display any authentication or consent user interface pages. An error is returned if an End-User is not already authenticated or the Client does not have pre-configured consent for the requested Claims or does not fulfill other conditions for processing the request. The error code will typically be login_required, interaction_required, or another code defined in Section 3.1.2.6. This can be used as a method to check for existing authentication and/or consent.
prompt=none is also referred to from the Session Management specification.

DocuSign authorization code grant - multi users in Docusign Account

I'm using Authorization Code Grant to authenticate from my cloud app to DocuSign. I followed the excellent directions provided by DocuSign. When I authenticate the user I get the DocuSign Login screen and consent dialog. If I then authenticate again somehow DocuSign decides the user hasn't changed and doesn't pop up the login and consent dialog. Usually this is acceptable because it is indeed the same user.
However, if I logout of my application and then (before closing browser) relog in to my application as a different user then I am expecting that when I request to authenticate to DocuSign that the login and consent will come up. That isn't happening and DocuSign returns user information for the original user.
What mechanism is DocuSign using to determine that the user hasn't changed? Is it browser cache? More importantly is there a way I can disable that when I am starting the authorization code grant so that I can authenticate the second user?
Please add query parameter &prompt=login in your initial url. This will show login page everytime.

What should the Authorization Server do when Resource Owner fails to authenticate him/herself in OAuth 2.0?

I am developing an app and I am trying to save user data to a third-party service. The service allows me to access the users' resources via OAuth. I have finished implementing the OAuth flow and it works as follow (when no error occurs):
I redirect the user to the authentication page of the service provider, providing the following parameters in the URL:
?redirect_uri=[my_redirect_uri]&client_id=[my_client_id]&response_type=code
The user authenticate him/herself
The service redirect the user to the redirect_uri and pass me the authorization code in the URL parameter: code=[authorization_code]
I get the access_token from the auth_code
I can now access the user data
You can see the diagram here.
I found out that for this particular service, when the user fails to authenticate him/herself (step #2), the Authorization Server immediately redirect the User-Agent to my redirect_uri and in the URL parameter I got error=access_denied.
I find this not a user-friendly experience because the user can make a typo or simply forget his/her credentials.
I checked the OAuth 2.0 Authorization Framework RFC. It seemed that there isn't any protocol on resource owner's authentication failure. I see in the RFC that there are protocols for Client authentication failure or Authorization failure. However, it is not stated how the Authorization Server should respond when it fails to authenticate the resource owner.
I did my own research by trying to login to Medium using Facebook OAuth. I see that when I fail to login, I am still in the Facebook authentication page, and Facebook notify me that my credentials is wrong. I can enter a wrong credentials up to 3 times, after which, the flow will break (the parameters in the URL associated with the OAuth disappears). When I enter the right credentials and deny Medium to access my profile, then, I was redirected to Medium with error=access_denied
Is what Facebook did the best practice? Is there a policy on the number of attempts allowable for resource owner authentication? What is the proper response when the Authorization Server fails to authenticate the resource owner?
The response with error=access_denied actually complies with the OAuth2 specification. The section (4.1.2.1.) on error responses for the authorization endpoint when using the authorization code grant lists several possible error codes and says the following about the access_denied:
access_denied
    The resource owner or authorization server denied the request.
(emphasis is mine)
What does not feel right is treating invalid credentials immediately as an error and not letting the user retry the password input in order to safeguard occasional typos. However, that's left as the discretion of the authorization server, there's nothing (that I'm aware) in the specification that dictates when should the error be returned so not allowing the user to retry, although okay by the specification, is possibly bad UX.
OAuth gives only a reccomandation on this case, it doesn't limit the number of attempts allowable for resource owner authentication.
If the authorization server observes multiple attempts to exchange an
authorization code for an access token, the authorization server SHOULD attempt to revoke all access tokens already granted based of the compromised authorization code.