JWT correct behaviour with invalid credentials - java

I would like to ask how to behave correctly when server receives user credentials which are not valid (username or password does not fit).
Should server send back an empty jwt token and set HttpStatus for 401
or is there any other preferable way?

Related

Is Spring 'authorization' header a misnomer, considering that it does authentication and not authorization?

In Spring, to verify the user credentials, 'authorization' header is used. Usually, user name and password are encoded using some algorithm(commonly base 64) and passed in this header. But, validating user name and password comes under authentication, does n't it? It means, this 'authorization' header is not appropriate. It should have been called 'authentication' header.
Read https://howtodoinjava.com/spring-boot2/security-rest-basic-auth-example/
With OAuth the Authorization header is used to send a JSON Web Token (jwt).
This token is the result of a authentication process and holds user's data like username, the issuer of the token and roles like admin. It should never contain sensitive data like password. Furthermore the token is signed by the issuer with a rsa key.
Spring uses this token for authorization. The signature is verified, so no one can claim roles by creating a fake token.
The roles eg can than be uses grant/deny access to certain methods.
This article shows an example application that might help you understand the concept:
https://www.baeldung.com/rest-api-spring-oauth2-angular

Programatic username/password access with KeyCloak using external IDP brokering

I'm using Identity Brokering feature and external IDP. So, user logs in into external IDP UI, then KeyCloak broker client receives JWT token from external IDP and KeyCloak provides JWT with which we access the resources. I've set up Default Identitiy Provider feature, so external IDP login screen is displayed to the user on login. That means that users and their passwords are stored on external IDP.
The problem occurs when I need to log in using "Direct Access Grant" (Resource Owner Password grant) programatically in tests. As password is not stored on KeyCloak, I always get 401 Unauthorized error from KeyCloak on login. When I tried to change user password it started to work, so the problem is that user password is not provisioned on KeyCloak and using "Direct Access Grant" KeyCloak doesn't invoke external IDP on programatic login.
I use the following code to obtain access token, but get 401 error everytime I pass valid username/password.
org.keycloak.authorization.client.util.HttpResponseException: Unexpected response from server: 401 / Unauthorized
Direct access grant is enabled for that client.
public static String login(final Configuration configuration) {
final AuthzClient authzClient = AuthzClient.create(configuration);
final AccessTokenResponse accessTokenResponse = authzClient.obtainAccessToken(USERNAME, PASSWORD);
return accessTokenResponse.getToken();
}
Is there any way it can be fixed? For example to call identity broker on "Direct Access Grant", so that KeyCloak provides us it's valid token?
The problem was that KeyCloak has no information about passwords from initial identity provider. They have a token exchange feature which should be used for programmatic token exchange.
External Token to Interanal Token Exchange should be used to achieve it.
Here is an example code in Python which does it (just place correct values in placeholders):
def login():
idp_access_token = idp_login()
return keycloak_token_exchange(idp_access_token)
def idp_login():
login_data = {
"client_id": <IDP-CLIENT-ID>,
"client_secret": <IDP-CLIENT-SECRET>,
"grant_type": <IDP-PASSWORD-GRANT-TYPE>,
"username": <USERNAME>,
"password": <PASSWORD>,
"scope": "openid",
"realm": "Username-Password-Authentication"
}
login_headers = {
"Content-Type": "application/json"
}
token_response = requests.post(<IDP-URL>, headers=login_headers, data=json.dumps(login_data))
return parse_response(token_response)['access_token']
def keycloak_token_exchange(idp_access_token):
token_exchange_url = <KEYCLOAK-SERVER-URL> + '/realms/master/protocol/openid-connect/token'
data = {
'grant_type': 'urn:ietf:params:oauth:grant-type:token-exchange',
'subject_token': idp_access_token,
'subject_issuer': <IDP-PROVIDER-ALIAS>,
'subject_token_type': 'urn:ietf:params:oauth:token-type:access_token',
'audience': <KEYCLOAK-CLIENT-ID>
}
response = requests.post(token_exchange_url, data=data,
auth=(<KEYCLOAK-CLIENT-ID>, <KEYCLOAK-CLIENT-SECRET>))
logger.info(response)
return parse_response(response)['access_token']
This example was very useful for me, i only want to add more info about the KEYCLOAK-CLIENT used for the token-exchange (for me authorization_client). I have KEYCLOAK as a broker for IDP ADFS.
First you need to enable the token-exchange feature adding 2 parameters in your keycloak startup command line (depending of how you do it)
-Dkeycloak.profile=preview
-Dkeycloak.profile.feature.token_exchange=enabled
The IDP (for me ADFS) tab Permissions with the token-exchange permission will be available.
Add a policy to the "token-exchange" provider permission, to the client KEYCLOAK-CLIENT
Add this previous policy to the "token-exchange" client permission
With POSTMAN you can test the authentication flow:
External IDP ADFS Login Username/password
Token Exchange

Spring Security login for 2FA - First check username and password, and then ask for 2FA code if required

I have set 2FA up with spring security. The problem is, at the moment the 2FA code must be entered in the same form as the username/password. Is there a way to ask for the username and password first, and then, if they are valid, ask for the 2FA code?
I have done the same in angularJs.
The logic:
When the user has 2FA enabled, on form submit with only username and password, instead of returning a bad credentials response (401) or a success response, I return a Status code (403) indicating the server understood the request but refused to fulfill it.
When angular receives this 403 status it hides the username and password field and shows the OTP field. At this point the username and password are still present as angular objects but only hidden.
When the user enters the OTP and clicks submit, I again make a post call and this time pass the username, password and OTP.

How to send back a JWT token with HttpURLConnection in java?

I am using an API to get some information. At the beginning of each session you need to get a JWT token to be able to send requests to the API. After I've got the token and I try to send a request, I get an error saying I'm unauthorized, which is fair since I did not attach the token in my request. The problem is that the documentation for the API does not explain how to do this, and I haven't been able to find it anywhere else either. How do I do this? I am doing this is Java and is using their own HttpURLConnection. Hopefully you understand what I mean.
Thank you in advanced!
It depends on how the web-service (API) wants to have the token represented.
Common are:
HTTP request headers (problem for XHR requests)
query parameters (bad idea because of caching/logging)
form fields (not universally useable)
URL segment (bad idea because of caching/logging)
certain cookies with the token as value (transparent) or
authentication header (typical)
The Authentication headers as defined in HTTP RFCs are typically be used with the Basic or Digest authorization scheme. In case a string (token) authenticates the bearer of that token, the "Bearer" scheme is used (for example defined for OAuth2 in RFC6750).
You would use
uc.setRequestProperty("Authorization","Bearer " + jwt);
for this.

How to check if username and password is correct on login when using HTTP Basic?

I have created a web service that uses HTTP Basic. I am developing an Android application that will present the user a login screen with a textfield for username and another for password. When correct username and password is provided the user will see a new screen.
How can I validate on login that the username and password is correct? Since the dashboard screen that the is taken to after successful login does not by itself needs data from the webservice I can't check if it fails.
Do I have to check against a URL in my application (sending a HEAD request) and see if it fails? Are there any conventions here?
Check the response String and look here HTTP status codes
You can also use for example a mozilla add-on like Poster to check the server response.
Ok i guess you need to apply validations on username and password.
Validation are decided by the server end i.e. how username and password should be
for instance USERNAME.
1) Should not be less than 2 characters and max. length is decided.
2) If Email is to be used as Username then validation for email i.e. mus contains #,. etc.
for Password
1) Length of password should not be less than 6 or no to be greater than 20.
2) May or may not contain special characters.
Ask your server end that how they like to receive the username and password and check if user supplied inputs are valid or not , if valid only then make a HTTP call otherwise show user his respective error validation message.
you can send your username and passwords using http get/post method and can validate this at srver side

Categories

Resources