I have a web app that uses OAuth2's Implicit Grant to authenticate.
I'd like to be able to keep my session active for a long time, using refresh tokens. But since I can't securely store a client_secret in a web app, I can't use the traditional Authorization Code grant.
Is it safe to use PKCE in place of the client_secret, or am I losing some level of security in doing so?
Yes. While PKCE is more secure than NOT using it; the Implicit Grant with PKCE still leaves the Access Token may be exposed to the Resource Owner and perhaps other applications residing on the same device.
PKCE primarily protects from when the attacker intercepts the authorization code returned from the authorization endpoint within a communication path not protected by Transport Layer Security (TLS).
Implicit Flow is only suitable for OAuth Client applications that are browser based or JavaScript NOT Mobile Devices or other Applications that could use a Authorization Code Grant
With implicit grant, you can use neither PKCE, nor refresh tokens. If you want to improve security, then you should add a back-end to your web application, which can store a client_secret (or use an alternative method of client authentication). PKCE would not be needed.
Related
I have been reading about OpenId Connect and their flows that are implicit flow, authorization code flow and hybrid flow.
I know that for example, the implicit flow is kind of insecure and should be used just in public clients like SPA application.
Now I´m trying to understand the Hybrid Flow that can be used for non-public applications like .Net MVC applications where you have a backchannel communication and thus you can save a secret password.
Reading about the Hybrid flow I know that it has 3 different types of response_type that can be:
code id_token
code token
code id_token token
For me, the best response_type would be code id_token where I can get the code in the front channel and then send that code to the Identity Server Provider and get the access token through the backchannel.
I've been searching for information on a real-world application of response_type=code id_token token, or code token, but other than reading that in these flows the first token/s are issued by the authorization endpoint which is the front channel and the final tokens that are issued by exchanging the authorization code are issued at the token endpoint, which is the backchannel and thus inherently accepted as being more secure, I fail to understand what you would use this for. Any information would be gladly accepted.
Why hybrid flow? The oft-documented rationale is that your app can immediately have info about the user via the id_token while the access token acquisition is still in flight. Technically this is true but it's still rarely used in the wild.
One real-world example is a Financial-grade API (FAPI) profile developed by a working group under the umbrella of OpenID Foundation. It recommends hybrid flow for security reasons. It's worth noting that the channel split "feature" of the flow is not enough on its own to provide the desired security properties, more "cooperation" from other moving parts is needed. From FAPI implementer's draft part 2:
This profile describes security provisions for the server and client
that are appropriate for Financial-grade APIs by defining the measures
to mitigate:
attacks that leverage the weak binding of endpoints in [RFC6749] (e.g. malicious endpoint attacks, IdP mix-up attacks),
attacks that modify authorization requests and responses unprotected in [RFC6749] by leveraging OpenID Connect's Hybrid Flow that returns
an ID Token in the authorization response.
and details
8.3.3 Identity provider (IdP) mix-up attack
In this attack, the client has
registered multiple IdPs and one of them is a rogue IdP that returns
the same client_id that belongs to one of the honest IdPs. When a user
clicks on a malicious link or visits a compromised site, an
authorization request is sent to the rogue IdP. The rogue IdP then
redirects the client to the honest IdP that has the same client_id. If
the user is already logged on at the honest IdP, then the
authentication may be skipped and a code is generated and returned to
the client. Since the client was interacting with the rogue IdP, the
code is sent to the rogue IdP's token endpoint. At the point, the
attacker has a valid code that can be exchanged for an access token at
the honest IdP.
This is mitigated by the use of OpenID Connect Hybrid Flow in which
the honest IdP's issuer identifier is included as the value of iss.
The client then sends the code to the token endpoint that is
associated with the issuer identifier thus it will not get to the
attacker.
8.4.3. Authorization response parameter injection attack
This attack occurs when the victim and attacker use the same relying party client.
The attacker is somehow able to capture the authorization code and
state from the victim's authorization response and uses them in his
own authorization response.
This can be mitigated by using OpenID Connect Hybrid Flow where the
c_hash, at_hash, and s_hash can be used to verify the validity of the
authorization code, access token, and state parameters. The server can
verify that the state is the same as what was stored in the browser
session at the time of the authorization request.
For a more technical description of these two attacks and countermeasures, see Single Sign-On Security – An Evaluation of OpenID Connect
For a realllly detailed description, take a look at OIDC Security Analysis paper.
The hybrid flow allows the backend to continue to act on the user’s behalf in an offline way (when the user is no longer present sending requests by browser) or independently of the frontend... doing other stuff in parallel. It can use the back channel exchanged refresh token to continue to get a new access token and work indefinitely.
Per the new security guidelines at https://oauth.net/2/grant-types/implicit/, the implicit flow is not recommended. Since ADAL.js uses the implicit flow, will it be affected and is it recommended to use ADAl.js implicit flow for new applications?
Yes, I agree that as per the new guidelines, the implicit flow is not recommending. Currently, ADAL js uses the OAuth 2.0 implicit flow and it does not return refresh token for security reasons(refresh tokens have longer lifetime than access tokens and are therefore more dangerous in the hands of malicious actors).
It is designed to return an ID token when the resource for which the token is being requested is the same as the client application. When an ID token is returned, it cached by the library.
So when we use authenticationContext.acquireToken(resource, callback), it allows the application to obtain tokens silently without prompting the user again. ADAL js uses a hidden Iframe to make the token request to Azure AD.
But to use PKCE flow, we can make a http post call to https://login.microsoftonline.com/tenant_id/outh2/authorize endpoint by passing code_challenge along with other parameters in the body and gets the authorization code. And use that code and make a call to https://login.microsoftonline.com/tenant_id/outh2/token endpoint by passing code_verifier along with other parameters in the body and gets the token.
If you are using SPA, and have no backend components or intend to invoke a web API via JavaScript, use the OAuth 2.0 implicit grant flow.
But if you have a backend component and you are consuming an API from the backend code then implicit flow is not a good fit. In that case you can use OAuth2.0 auth code grant flow or OAuth2.0 client credential grant flow, it provides the ability to obtain tokens that reflect the permissions assigned to the application itself.
I'm currently trying to implement the OAuth 2.0 authorization code grant on a public client/native client (Android App).
Since it is impossible to store the client_secret on the device, I wanted to use this grant type with rfc7636 / Proof Key for Code Exchange by OAuth Public Clients (PKCE).
I'm using wso2 5.3.0 IAM in the backend.
The Authorization step works perfectly fine, but I'm not able to get the Access Token without a client_secret: invalid_request, Missing parameters: client_secret
Did I misunderstand the authorization code grant with PKCE wrong or did I miss some configuration in the IAM?
In comparison: It is possible with auth0.
Best Regards,
Robert
Even if you use the authorization code flow, client_secret is required at the token endpoint if the client type of your application is confidential. "4.1.3. Access Token Request" in RFC 6749 says as follows:
If the client type is confidential or the client was issued client credentials (or assigned other authentication requirements), the client MUST authenticate with the authorization server as described in Section 3.2.1.
So, change the client type of your application to public. I don't know WSO2, but I guess that it provides settings menu to switch the client type like below.
(screenshot of Authlete's web console)
The definitions of confidential clients and public clients are described in "2.1. Client Types" in RFC 6749.
Yes, the client_secret is mandatory in WSO2 IS implementation due to the Apache OLTU library that has been used internally to implement the OAuth2 feature.
Currently there is no way to register an application as a public client as explained.
However that doesn't mean there are necessarily any security pitfalls. Basically what the recommendation says is, not to embed the client_secret in a mobile app, because it makes it vulnerable. It doesn't provide any additional security for protected backend resources, because the client request is anyway not authenticated using client_secret. If you just treat the "Base64(client_id:client_secret)" as one single string it doesn't make any difference in the protocol or security of the protocol.
So when using WSO2 IS with mobile applications, following recommendations need to be followed.
Use authorization code grant type, which requires the client_secret.
Use PKCE (after WSO2 IS 5.2.0)
If you have other type of clients or channels for the same applications, e.g. like web, then register them as a separate service provider in IS and generate a separate pair of client_id, client_secret for them.
Disable "client_credentials" grant type for the particular OAuth2 mobile client you register in WSO2 IS, so that those apps can't get an access token without user authentication.
Going one step further, if you need to have unique client credentials for each instance of the mobile applications then use OAuth2 Dynamic Client Registration (DCR) to generate client credentials on the fly.
By following above 5 recommendations, it gives you the same level of security as recommended in the specification.
For Authorization grant flow you can send the request with empty client_secret. Try putting empty string like this client_secret='' and it should work as expected. You cannot request TOKEN_URI without client_secret parameter.
PKCE is used to protect theft of authorization code, Authorization code is valid for 10 minutes, when auth code is redeemed for access_token we also send code_verifier to make sure the auth code is not stoled by someone. code_verifier and code_challenge are generated together and code_challenge is used while requesting for auth code & code_verifier is used while requesting for access_token
From section 1.3.1:
The authorization code provides a few important security benefits,
such as the ability to authenticate the client, as well as the
transmission of the access token directly to the client without
passing it through the resource owner's user-agent and potentially
exposing it to others, including the resource owner.
Since authorization code allows for authenticating the client (as an additional security measure), why isn't it called authentication code?
It is primarily called authorization code because OAuth 2.0 is about authorization and not about (user) authentication.
It doesn't actually authenticate the client in the traditional "static" or "pre-established" sense. It just makes sure that the client requesting the token is the same as the that the authorization response was sent to.
In fact there's a separate set of client authentication options that can be applied to actually authenticate the client to the token endpoint in the classic sense.
I need to implement Authorization/Authentication for an Angular2 Client Side WebApp to talk to a Resource Server(WebApi).
I am investigating IdentiyServer4 and choosing a Grant Type / Flow. HERE
Resource Owner Password Credentials Grant(What we use now.) "This is so called “non-interactive” authentication and is generally not recommended".
Authorization Code & Hybrid <- Solution to Implicit Flow not allowing Refresh Tokens.(Seems fairly complex to me. But is this the way to go?)
Implicit Flow - Recommended for SPA's everywhere I look. But does not support Refresh Tokens..
With Implicit Flow, how do I not require the user of the SPA to have to type in a password every say 3600 sec? A recommended access_token lifetime. I presume there is something I do not understand about getting the new authorization URL.
Resources I have looked at.
IdentityServer4 Grant Types
Implicit Grant Flow for Client-Side Apps
A Guide To OAuth 2.0 Grants
SO - Oauth2 Implicit Flow with single-page-app refreshing access tokens
Thanks for the answer Scott. I have some reading to do.
Getting Started with IdentityServer4
When using the Implicit flow you can still use your own cookie lifetimes (ie longer than 3600 seconds). To get around access tokens expiring, you can use the fact that the user is still authenticated within IdentityServer to fetch another access token, without the need for refresh tokens.
The IdentityModel OpenID Connect JS Client does this by firing an event just before access token expiration and using an iframe to make a fresh authentication request to IdentityServer. If the user is still logged into IdentityServer (which has a different, typically longer lived cookie than your own client application), then IdentityServer sends back fresh tokens just like a normal authentication request. This happens in the background with no interaction from the user and no interruption.
Check out the automaticSilentRenew functionality in this library for implementation specifics.
By the way, the Implicit, Authorization Code and Hybrid grant types, in the case of IdentityServer, are OpenID Connect grant types. Resources referring to the OAuth versions may not apply to your use case.