Restrict openid-connect userinfo request from unknown source - oauth-2.0

How to restrict openid-connect request from the unknown source.
If we've Access Token available anyone can request for userinfo (we are saving user information and claims into userinfo) which we want to restrict.
means, the request we should allow from known clients only.
Note: we are using Keycloak as Identity Server
Please help!!

First and foremost, access token must be protected as same as user credentials. What OAuth2.0 framework give us is the ability to replace username/password based authentication/authorization with dynamically generated tokens. Thus these tokens must be protected. That is why TLS is a must for token transmission.
RFC6749 section 10.3 - Access token credentials (as well as any
confidential access token attributes) MUST be kept confidential in
transit and storage, and only shared among the authorization
server, the resource servers the access token is valid for, and the
client to whom the access token is issued. Access token
credentials MUST only be transmitted using TLS as described in
Section 1.6 with server authentication as defined by [RFC2818].
So if you are worrying over access token misuse, you must first worry about adopting token based communication. Your clients must be secure enough not to misuse the tokens.
Also one other thing you can do is to enable CORS headers to restrict the access to the endpoint. But, this is only after protecting the tokens.!
p.s Alternatively, network configurations can be set to allow only the known/valid IP addresses to communicate to your back end. But that is out of the OIDC protocol.

Related

Why does machine-to-machine interaction in OAuth2 disallow the refresh_token grant without providing the client_secret?

We are implementing JWT-based authentication for our APIs, using Keycloak as an identity provider and token endpoint.
We found the idea of OAuth2 attractive, as it reduces the need for long-lived credentials to travel over the network. Instead of issuing our end-users an API key which they would put into a header for every request they send our way, they can use a client ID and secret to request an access token with a relatively short lifespan.
I mistakenly assumed that the clients would also receive a refresh token and be able to get new access/refresh token pairs using that (and not using the client secret). This would further lessen the need for the client secret to go back and forth over the network.
Here's some background for my initial reasoning:
Client gets access/refresh tokens with client credentials
Client uses access token until expiry
Client uses refresh token to obtain a new access/refresh pair.
The old refresh token is invalidated (this is possible to do with Keycloak by tweaking max sessions).
Retrieving an access/refresh pair with static credentials similarly invalidates a refresh token.
In this case an attacker sniffing network traffic would be very lucky to ever see static credentials passed and the compromise of credentials (whether static or refresh) is very visible, since the legitimate client would notice that its refresh token no longer works.
However, from what I gathered in the standards, the generally accepted way for machine-to-machine interaction to happen under OAuth2 is with the client credential grant type, which does not return refresh tokens and the client must request a new access token with its credentials every 10-15 minutes or so.
This leaves me confused: is this not, basically, another convoluted type of basic auth then, where we repeatedly send static credentials over a potentially insecure network? Sure, most requests are done with an access token, but an attacker will know for sure that every 10-15 minutes the static credentials will be sent to the authorization server.
Is there another way to do machine-to-machine interaction which is better secured against an attacker, who has managed to sniff our traffic? To be more specific, something which avoids, or mostly avoids sending static credentials.
Regarding your question about another way to do machine-to-machine interaction which is better secured against an attacker, who has managed to sniff our traffic, there are alternative authentication methods that a client can use.
The default client auth method is based on a shared key, called client secret in OAuth 2.0 spec. Client id and secret must be sent to the auth server to obtain an access token. This has to happen every time previously issued access token expires. This increases the risk of client secret exposure. This method does not require a refresh token as the client is obtaining a token for itself. This method is performed over SSL which reduces the risk of exposure. In addition, active IP monitoring further reduces the risk of compromised client secret. Client secret can be invalidated if a request is issued from an IP that has not been seen.
However, a more secure alternative to a shared client key is a private key and a signed JWT authentication. A client uses a private key and signs a set of assertions in a JWT token. This JWT is sent with the token request. The JWT is extremely short lived with expiry set to a few seconds from the issue. The auth server is configured with a corresponding public key and is able to validate JWT signature this authenticating the client's request. This JWT is a single use token and should include a unique token id. Auth server can persist unique JWT id until expiry to prevent token replay.
In addition to a short lived JWT, client IP monitoring can be implemented so that the client is only allowed to use this key from an established set of IP addresses or from previously observed set of IP addresses.
OAuth 2.0 also provides for a client to authenticate via a X.509 certificate submitted to the auth server during TLS handshake.
https://datatracker.ietf.org/doc/html/rfc8705

Is a shared secret even necessary when using RSA256 (asymmetric) signed JWT?

One often reads that the ResourceOwnerCredentials Flow is bad because there can not be a secret key involved with an untrusted client (lika a Javascript or mobile Application).
Is this even valid if the tokens are signed asymmetrically and can be validated by the client using the public key JWK (Json Web Key) provided by the OAuth 2.0 server?
You have misinterpreted the "Resource Owner Password Credentials Grant" (link to spec.).
What this flow does is, substitution resource owner's (if it's a person, it will be the end user) credentials with authorisation code. As the specification says it can be used to replace legacy systems which for example use basic authentication. And to this to be done, trust should be established between client and resource owner. Found a good article which you can read more on this link
On the other hand, Client Credentials Grant is a grant which requires client to obtain and maintain (link to spec.). And this grant is only applicable to confidential clients
The client credentials grant type MUST only be used by confidential
clients.
I believe you have confused about two different grant types. As you have already seen, mobile applications and JavaScript applications are public client. So the client credential grant cannot be used for them.
Furthermore, once can indeed validate tokens using public key but to do that one should obtain tokens by completing a valid flow.
For a confidential client, shared secret can be used to encrypt the token. But this cannot be done for a public client as they cannot maintain a shared secret.
Anyway here are use cases for using client authentication (as described in specification : Client authentication)
Enforcing the binding of refresh tokens and authorization codes to
the client they were issued to. Client authentication is critical
when an authorization code is transmitted to the redirection
endpoint over an insecure channel or when the redirection URI has
not been registered in full.
Recovering from a compromised client by disabling the client or
changing its credentials, thus preventing an attacker from abusing
stolen refresh tokens. Changing a single set of client
credentials is significantly faster than revoking an entire set of
refresh tokens.
Implementing authentication management best practices, which
require periodic credential rotation. Rotation of an entire set
of refresh tokens can be challenging, while rotation of a single
set of client credentials is significantly easier.
As a fact, confidential client allows you the flexibility of altering client authentication by changing the shared secret.

What are the limits of public clients in OAuth 2.0

OAuth 2.0 specifies two client types:
public (client_id)
confidential (client_id:client_secret)
and section 2.2 says:
The client identifier is not a
secret; it is exposed to the resource owner and MUST NOT be used
alone for client authentication.
While it is clear to me that public clients are primarily used for the implicit flow, there is more to this than it seems. When performing the auth code flow, we first request the authorization endpoint with our client_id, no secret required. Then, after getting the user's consent and the authorize code, we request the token endpoint. According to spec, we are able to request this endpoint without a client_secret:
client_id
REQUIRED, if the client is not authenticating with the
authorization server as described in Section 3.2.1.
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.
...
The authorization server MUST:
...
o ensure that the authorization code was issued to the authenticated
confidential client, or if the client is public, ensure that the
code was issued to "client_id" in the request,
So basically this section says that we are able to request this endpoint without a client secret. Now, it doesn't say anything about refresh tokens other than that those may be included in the request.
Refreshing an access token mentions:
Because refresh tokens are typically long-lasting credentials used to
request additional access tokens, the refresh token is bound to the
client to which it was issued. 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 basically we're allowed to refresh the access token without client authentication.
Now, what confuses me is that the implicit flow does not allow issuing of refresh tokens:
The authorization server MUST NOT issue a refresh token.
It doesn't say explicitly why we can't do that, only that we're not allowed to. My reasoning is that this isn't allowed because the client can't be trusted. But since the authorize code flow is allowed for public clients, why do we actually need the implicit flow, if the same thing can be achieved with a public client, plus getting a refresh token?
I'd be very glad if someone could clarify this.
You are allowed to request/refresh access token without client secret at your own risk. Or we can say it depends on your security requirements. The spec only clarifies client authentication for confidential clients, basically if the client is confidential. it MUST be authenticated by the server.
For public clients, the spec says:
The authorization server MUST NOT issue client passwords or other
client credentials to native application or user-agent-based
application clients for the purpose of client authentication.
So public clients can't even have a secret to be authenticated with. And then the spec also says:
When client authentication is not possible, the authorization server
SHOULD employ other means to validate the client's identity -- for
example, by requiring the registration of the client redirection URI
or enlisting the resource owner to confirm identity. A valid
redirection URI is not sufficient to verify the client's identity
when asking for resource owner authorization but can be used to
prevent delivering credentials to a counterfeit client after
obtaining resource owner authorization.
Also you may look at PKCE.
Get back to your question, I think you are misunderstanding:
According to spec, we are able to request this endpoint without a client_secret.
Not quite right, you must authenticate confidential client and you can't authenticate public client using a client secret (it does not have one).
The authorization server MUST NOT issue a refresh token.
I think it is all matter of security. In implicit grant, we are operating under a presumably unsafe environment. Exposing refresh token could harm your system, since we already expose access token in this grant type (Please read security consideration for access token).
But since the authorize code flow is allowed for public clients, why do we actually need the implicit flow, if the same thing can be achieved with a public client, plus getting a refresh token?
They are meant for completely different use cases. From https://oauth.net/2/grant-types/implicit/
The Implicit grant type is a simplified flow that can be used by public clients, where the access token is returned immediately without an extra authorization code exchange step.
It is generally not recommended to use the implicit flow (and some servers prohibit this flow entirely). In the time since the spec was originally written, the industry best practice has changed to recommend that public clients should use the authorization code flow with the PKCE extension instead.
Lastly, I suggest you to play with this site to get a better understanding of different grant types.

Why not send access and refresh tokens simultaneously (OAuth2)?

Why can't the client simply send both the access and refresh tokens together for every authorized request? If the access token is expired, it wouldn't require two additional trips to retrieve a new access token and finally making the relevant request.
I realize this operation is amortized, but it would lessen the number of requests for very short access tokens. And under SSL, I don't see how adding the refresh token makes this any more vulnerable. Or does it?
I think the main reason is that the refresh token and the access token are sent to different places. The access token is sent to the resource server and the refresh token is sent to the authorization server. In the general case, there's nothing that the resource server can do with the refresh token.
Some reasons:
The access token provides an abstraction layer, replacing different
authorization constructs (e.g., username and password) with a single
token understood by the resource server. This abstraction enables
issuing access tokens more restrictive than the authorization grant
used to obtain them, as well as removing the resource server's need
to understand a wide range of authentication methods.
https://www.rfc-editor.org/rfc/rfc6749#section-1.4
Having the resource servers understand refresh tokens means more work for them when it can / should be abstracted away (by the authorization server).
...
Because refresh tokens are typically long-lasting credentials used to
request additional access tokens, the refresh token is bound to the
client to which it was issued. 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.
https://www.rfc-editor.org/rfc/rfc6749#section-6
A refresh request requires client credentials. The resource server shouldn't have to ever see the client's credentials.
Refresh tokens are meant to be long-lasting, while access tokens aren't (or shouldn't be).

Why must we "change temporary credentials for token credentials" in OAuth?

Can't the server just "upgrade" the temporary credentials to token credentials and retain the same key and secret?
The client can then start doing authenticated calls right away after the recieving the callback from the server stating that the temporary credentials has been "upgraded".
Of cause if the temporary credentials have not be upgrade (i.e. client doesn't wait for callback) the authenticated call fails.
So the question is why make an extra call to the server after the callback to "exchange" temporary credentials for token credentials?
You could implement OAuth in that way, but as I understand it, separating Request Tokens from Access Tokens does provide an extra layer of security.
From the Beginner's Guide:
OAuth includes two kind of Tokens:
Request Token and Access Token. Each
Token has a very specific role in the
OAuth delegation workflow. While
mostly an artifact of how the OAuth
specification evolved, the two-Token
design offers some usability and
security features which made it
worthwhile to stay in the
specification. OAuth operates on two
channels: a front-channel which is
used to engage the User and request
authorization, and a back-channel used
by the Consumer to directly interact
with the Service Provider. By limiting
the Access Token to the back-channel,
the Token itself remains concealed
from the User. This allows the Access
Token to carry special meanings and to
have a larger size than the
front-channel Request Token which is
exposed to the User when requesting
authorization, and in some cases needs
to be manually entered (mobile device
or set-top box).
So, as I understand it, by limiting the Access Token to a channel directly between the consumer (your service) and the provider (the service you're gaining access to), you can obtain a secure Access Token (that is, one the attacker doesn't have) even if the user's machine or the user's network connection to your service is compromised. If the Request Token were simply upgraded, then anyone sniffing the user's network connection could easily obtain the Request/Access Token, which we'd prefer to keep secret since it can be used (with your consumer token, of course), potentially for a very long time, to access the user's data. A server-to-server connection is often more secure.
Also, as is pointed out above, this lets you have a much longer key in cases where the Request Token actually has to be typed out by the user (and so is probably very short).

Resources