What types of attacks do IdentityServer client secrets protect against? - client-server

I am trying to understand the purpose(s) of client secrets. Is it to prevent someone from creating a fake server that pretends to be my server? If not, what is it? And does it protect against anything else?

The client secret is used to identify the application that requires an access token in order to access a resource on behalf of the user. Only clients registered in the authentication service can request access. Not only will user authentication be necessary, the client application must also be legitimate. Otherwise someone could impersonate the client application.
This type of client authorization should only be used by confidential clients ([OAuth2 Client Types][2]).
confidential
Clients capable of maintaining the confidentiality of their
credentials (e.g., client implemented on a secure server with
restricted access to the client credentials), or capable of secure
client authentication using other means.
public
Clients incapable of maintaining the confidentiality of their
credentials (e.g., clients executing on the device used by the
resource owner, such as an installed native application or a web
browser-based application), and incapable of secure client
authentication via any other means.
When using flows with clients that cannot guarantee the confidentiality of this secret (i.e. implicit), the identity of the client cannot be verified. In those cases it can be verified by means of the redirection URI. As an additional measure, it should limit the exposure of refresh tokens.
Officially it is no longer recommended to use the implicit flow for security reasons, the recommendation for this type of clients is Authorization Code + PKCE extension. [See OBBA document][1]
For authorizing users within a browser-based application, the best current practice is to
o Use the OAuth 2.0 authorization code flow with the PKCE
extension
o Require the OAuth 2.0 state parameter
o Recommend exact matching of redirect URIs, and require the
hostname of the redirect URI match the hostname of the URL the app
was served from
o Do not return access tokens in the front channel
[1]: https://datatracker.ietf.org/doc/html/draft-parecki-oauth-browser-based-apps-02)
[2]: https://www.rfc-editor.org/rfc/rfc6749#section-2.1

Sometimes you have some ApiResources which called by Clients and there is no any user in the flow. for example fetch instagram's post using instagram's api. now instagram wants to control client behavior so client should be authorized for instagram befor any api call. in this situation you need define some secret for each client to identify them.
This an example of client's secret usage.

Related

spring boot security use keycloak sessions

I'm new to security and I'm trying to understand how to implement proper security without any overkill.
Below are my questions.
I don't want to allow 3rd party clients to use my API and hence I don't see any importance of OAuth 2.0. Hence I'm looking to use the sessions generated by keycloak (or Ory Kratos) in my Spring Boot Security. Any guidance on how to do that.
I have come across an application https://opstra.definedge.com/ which security is implemented using keycloak (can see the URL pattern). But in the requests, I can't see any JWT token in the chrome DevTools Network Tab while performing any network requests. I think they are implementing it the way I wanted. Any overview on how it is implemented.
I'm not architect at definedge, but I'm pretty sure they do not use Keycloak sessions in Opstra (they would have to run Opstra inside Keycloak servlet for that). It more looks like they use OAuth2 to authenticate users from a Java client and that this client has sessions of its own enabled (JSESSIONID cookie for opstra.definedge.com VS sso.definedge.com). It is quite possible that this java client uses access-tokens to authorize requests to resource-server(s), we just can't see it from the browser.
Restricting the clients allowed to consume your API has little to do with authorization method:
with basic authorization header, any client with login and password can access
with Bearer authorization header, any client with a valid token can access (which you already had anticipated)
even JSESSIONID cookie can be set for any origin (I believe), in which condition any request from the same browser would be authorized, whatever the web client.
Restricting your API clients is more about CORS configuration, which aims at just that: filtering which origins (host + port) can access which resource location (URL)
There is a notion of confidential client in Keycloak where the client must provide a password in addition to client-id to exchange authorization codes for access-tokens, but this does not apply to rich clients (clients running on devices you cannot trust): Angular, Vue, React, native mobile apps, etc. code can be reversed enginereed to read that password. But it is possible to configure a Java client of your own as "confidential" and as so, allow this client only to get access tokens to query resource-server (API).
OAuth2 comes with much more than just easing multi-client scenarios and JWTs with session-less java applications greatly ease horizontal scalability and fault tolerance. You should read this article for a refresher on
OAuth2 (and its value)
resource-server security configuration (with CORS)

Token authentication and SSL

I'm relatively new to this area of securing API. Most of my career was in developing internal products for the use of the organization, or joining a product that has already implemented security (which usually does not change)
When reading about JWT and Identity server, I understood the role of signing and the need to separate authorization and authentication. But, one thing strikes me as odd:
If my user is about to get a signed token and use it to authenticate himself, and there is a "Man in the middle", listening and copying that token, could he impersonate my user? (I believe the answer is yes)
So my best option here is to use SSL on every call to my API. The token being temporary and all is not much less of a threat to security.
So, my question here is:
If I end up using SSL on my API calls, what is the signing good for? with SSL the traffic is hidden anyway and no one could tamper with it. The browser can possibly use the username and password as plain text and they won't be exposed.
What am I missing here?
I think all boils down to what purpose JWT serves in OpenID Connect protocol (OIDC).
In OIDC, ID token is a JWT. And if you go through RFC7519 - JSON Web Token, then you come across Trust Decisions section.
The contents of a JWT cannot be relied upon in a trust decision
unless its contents have been cryptographically secured and bound to
the context necessary for the trust decision
From OIDC perspective, trust decision is to authenticate the end user based on claims contained in the ID token. This can be only done if validation adhere to JWT specification. So basically it is a requirement by OIDC protocol and JWT specification.
Now about SSL. OIDC contains several other calls required to obtain final token response. These calls contain client identifiers, secrets and authorization code (depending on the flow). OIDC is built on OAuth 2.0 and OAuth 2.0 mandate SSL (TLS being the new name). Thus OIDC too require SSL.
In combination, SSL (TLS) prevents attacks during request and responses flow in wire. And JWT's signature guarantee token's authenticity independent of how it was received or which component of your application process it.

Which information gets sent in each API request using OIDC

I'm writing an API back-end that I want to use OpenID Connect (OIDC) to secure. I've been reading the documentation but I'm still a bit confused what process applies to each and every API request. The Open ID Connect code flow appears to be:
Which I'm fine with, as a one-time process. My back-end API sees an authorization code in the HTTP headers, and sends a request to the authorization server to get the id token. Assuming this validates OK, the data requested is returned in the API response.
But assuming the same user will then be making lots of requests to this API, what happens in subsequent requests? Is there some sort of session created in this mechanism? Do I continue to receive the same authorization code? Do I have to keep sending these back channel requests to the authorization server?
Or should I even output the JWT id token as a cookie? In this way I get the self contained id token coming back in future requests, with no need of a server side session, or further round trips.
I've been reading the documentation but I'm still a bit confused what
process applies to each and every API request
It is not the API that should follow OpenID connect protocol. It's the client that should do it.
My back-end API sees an authorization code in the HTTP headers, and
sends a request to the authorization server to get the id token.
Assuming this validates OK, the data requested is returned in the API
response.
Authorization code must be used by client application and not by the API endpoint. Also, authorization code must never be exposed to other entities.
You should use id token sent with OpenID Connect to authenticate the end user from your client application. To access API, you should use access tokens.
What to do in API endpoint ?
I think this is where you struggle. Your client application should send a valid access token to get access to API endpoint. From API endpoint, you can use OAuth 2.0 introspection endpoint to validate the tokens.
RFC7662 - OAuth 2.0 Token Introspection
This specification defines a protocol that allows authorized
protected resources to query the authorization server to determine
the set of metadata for a given token that was presented to them by
an OAuth 2.0 client.
Note that, OpenID Connect is built on top of OAuth 2.0. This means you can use anything defined in OAuth 2.0, including introspection endpoint. Use this endpoint to verify the access token validity.
What if you want end user details ?
OpenID Connect defines a user info endpoint
User info endpoint
The UserInfo Endpoint is an OAuth 2.0 Protected Resource that returns Claims about the authenticated End-User. To obtain the requested Claims about the End-User, the Client makes a request to the UserInfo Endpoint using an Access Token obtained through OpenID Connect Authentication. These Claims are normally represented by a JSON object that contains a collection of name and value pairs for the Claims.
Here also, you use access tokens to get user information from this endpoint. The response will let you know the end user to which this token was issued.
Depending on your specific API requirement, you can do a token introspection or obtain user information from user info endpoint. Once that is done you may go ahead and authenticate a session. You might use both endpoints if you need all available information.
Alternatively(instead of sessions) your API can maintain an access token cache. This will remove the need to validate tokens in each an every API call. But be aware that tokens have expiration time. You must consider about token expiration if you are choosing this solution.
p.s - Client vs Resource server
In OpenID Connect and OAuth 2.0 terms, a client could be a simple web page, desktop application or could be even server hosted application.
client
An application making protected resource requests on behalf of the
resource owner and with its authorization. The term "client" does
not imply any particular implementation characteristics (e.g.,
whether the application executes on a server, a desktop, or other
devices).
Obtaining tokens and using them is the duty of the client application.
On the other hand, resource server contains protected resources,
resource server
The server hosting the protected resources, capable of accepting
and responding to protected resource requests using access tokens.
Resource server exchange it's resources to access tokens. If we match the same scenario to basic authentication, access tokens replaces username/password sent with authentication headers.
Typically you'd secure a (pure) API with OAuth 2.0, not OpenID Connect. The Client accessing your API should obtain an OAuth 2.0 access token and in order to do that it may choose to use OpenID Connect to obtain that token. That is all independent of the API, which will only see the access token. The API (or Resource Server in OAuth 2.0 terminology) is not depicted in your diagram.

What the configuration of spring-security-oauth2 authorizedGrantTypes means in practice?

For example on the default jhipster UAA configuration we have:
clients.inMemory()
.withClient("web_app")
.scopes("openid")
.autoApprove(true)
.authorizedGrantTypes("implicit","refresh_token", "password",
"authorization_code")
.and()
.withClient(jHipsterProperties.getSecurity()
.getClientAuthorization().getClientId())
.secret(jHipsterProperties.getSecurity()
.getClientAuthorization().getClientSecret())
.scopes("web-app")
.autoApprove(true)
.authorizedGrantTypes("client_credentials");
So what does "authorizedGrantTypes" really means in practice? The first client "web_app" will have different types including refresh and so the second will be able to generate a token as client_credentials. What is the difference?
Another question, what is the purpose of the second client authentication which uses "client_credentials" ? Since this is disconnected from the real users stored. microservice to microservice communication? Looks bad if the configuration is deployed on spring cloud (client and secret hard coded configuration) to allow any external authentication via the gateway. How to prevent this?
OAuth 2.0 grant types are the different "ways" your client applications can obtain tokens.
There are a bunch of articles explaining it better, but here is a summary :
authorization_code is the "classic" OAuth 2.0 flow, where the user is asked for its consent through redirections. The client application is strongly authenticated because it has to send all its credentials (client_id+ client_secret + redirect_uri) before it can get a token.
implicit is almost the same as authorization_code, but for public clients (web apps or installed/mobile applications). The flow is almost the same from the user standpoint, but with weaker client authentication. The redirect_uri is the only security, as the client receives the access token through redirection + request parameters.
password is straight forward : the client application collects the user credentials, and sends both the user credentials (username+password) and its own credentials (client_id+client_secret) in exchange for a token. This flow mixes authorization with authentication, and should only be used when there is no other choice (i.e. your own installed/mobile application, where you don't want users to switch back and forth between native app and browser). You should never allow a third party to use this flow.
With all these flows, the user is asked for its permission, one way or another. The token given to the client allows it only to access that single user's data.
The client_credentials grant is different, as it does not involve a user. It is a drop in replacement for HTTP Basic.
Instead of sending a username (client_id) + password (client_secret) for every request, your client sends its credentials in exchange for a token.
It is used in server-to-server communications, where you want to know "which application is calling" by giving it distinct credentials, but you don't tie its authorization with a specific user.
Some examples :
a command line application (batch) or worker process consuming secured services. This kind of application probably processes a bunch of user data at once, and it cannot request each user's consent. The service called has to know "who" is calling in order to allow the client application to access anything.
a third party / external client of your API wants to know informations that are not linked to user data (for example : usage stats, quotas, billing...)
a third party / external client with special privileges who can access all your users' data
Note : In service to service communication, you should relay the token received from the outside instead of having each intermediate application request its own token.

REST authentication, Best approach

Background:
We are building system that required login information for all pages. the application is designed to be Restful application using codeigniter as Phil Sturgeon library.
Scenario:
- username & password is required when a user called any page [Client]
- Authentication is needed where any Api call is fired
I a bit confused how to migrate or do the above scenario, And what are approach to authenticate the application.
A simple way to authenticate users in a RESTful API is using HTTP Basic or Digest Auth. In this setting the user credentials are sent via the Authorization header in a form of username:password as Base64 encoded hash to the server.
As the principles of REST state that the communication between client and server should be stateless, the client has to sent the authorization on every request. In practice this means that you often store the credentials in a session on the client side (as you don't want to the user to enter his credentials on every request). Please note that you should only do this via an secured connection using HTTPS!
To authenticate the application you could use a token based system, such as an API-Key. This means any request would be signed using additional request parameters. If the number of applications is finite and known, you could alternatively simply identify them by their IP.
You could also take a look at OAuth.
Request the login and password for every page is more suitable and more secure(that what I do in my projects), using 'virtual' and stored session in the database may be a second solution but not a good because it will be an additional charge for the DB.

Resources