I am developing a REST API secured via OAuth2 with Spring that will be used from an Android application (the client). In order to access any endpoint of my API, a OAuth2 access token is required and handed over to the endpoint via Authorization Header in a way similar to this:
"Authorization" - "Bearer accesstokenhere"
In order to acquire an access token, a username and password must be provided, as well as a client ID and client secret (they represent the Android app). The clientID and client secret are handed over to the token endpoint via Authorization Header in a way similar to this, which is specified by Spring:
"Authorization" - "Basic clientId:clientSecret"
If the client ID and client secret match a client defined on the server and if the user exists and the password is correct, access token and refresh token are returned.
Now my question is how I can securely store my clientId and client secret inside the Android application, making sure someone who reverse engineers my app does not get access to them?
Also, if I were to develop an iOS application (a second client), would it be wise to use a different clientID and client secret from a security POV?
You can't - even if there was a way, I could still just inspect the payload on the wire to determine the values. See section 8.5 of the OAuth 2.0 for Native Apps
Secrets that are statically included as part of an app distributed to multiple users should not be treated as confidential secrets, as one user may inspect their copy and learn the shared secret. For this reason, and those stated in Section 5.3.1 of [RFC6819], it is NOT RECOMMENDED for authorization servers to require client authentication of public native apps clients using a shared secret, as this serves little value beyond client identification which is
already provided by the "client_id" request parameter.
Your client id/secret parameters are just providing the identity of application making the request, as such it is recommended you'd want to create a different client for your iOS application, both from a security isolation point of view + for any analytics you want to gather about use of your application (e.g. 'how many sign in attempts are you retrieving by client id?' etc)
However, a threat actor could reverse engineer your settings, take your client id + secret and then start hitting your token endpoint with a username/password combo to attempt to brute force your application. If an endpoint accepts these values and returns a success/failure code, this is a useful attack vector for someone trying to compromise your system.
The current recommended approach is to use the 'Authorization code flow'
The best current practice for authorizing users in native apps is to
perform the OAuth authorization request in an external user-agent (typically the browser), rather than an embedded user-agent (such as one implemented with web-views).
Previously it was common for native apps to use embedded
user-agents (commonly implemented with web-views) for OAuth
authorization requests. That approach has many drawbacks,
including the host app being able to copy user credentials and
cookies, and the user needing to authenticate from scratch in each
app. See Section 8.12 for a deeper analysis of using embedded
user-agents for OAuth."
Have a look at AppAuth for Android for more information,