Create JWT Blacklist in Spring Cloud Gateway - spring-oauth2

I integrated spring cloud gateway with oauth2 login. After logout in scg, the user still can access resource server because the user has valid token. I need to invalidate this valid token in some way. there is blacklist solution as my researches (https://stackoverflow.com/a/53994938/5079581) and i will implement this.
by creating filter, i take jwt in step of "/logout" and put it to blacklist.
public class ExampleWebFilter implements WebFilter {
#Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
ServerHttpRequest request = serverWebExchange.getRequest();
String uri = request.getPath().pathWithinApplication().value();
HttpHeaders headers = request.getHeaders();
if(uri.equals("/logout")) {
List<String> auth = headers.get("Authorization");
}
return webFilterChain.filter(serverWebExchange);
}
}
auth list always returns null. i think that my filter works before token relay filter. how can i access the jwt at gateway? is there any code sample or demo for this? Thanks.

In spring cloud gateway + security oauth2 integration, JWTs are stored in gateway as session. At first, i thought there was an error about saving JWT as session, as it becomes stateful. But, when you logged out, this session is removed and there is no JWT anymore, so there is no need to create blacklist. this way of working is a clever solution.
So, what was my problem? I had 2 seperate servers (gateway, oauth2 server). two sessions are created as a result of the operation. SESSION for gateway, JSESSION for oauth2 server. when you logged out at gateway, only SESSION is removed, but JSESSION is still alive. because of that, the gateway goes oauth server(and still signed in oauth2 server) and get new JWT.
To log out completely in system, you also need to logged out from ouath2 server at the same time.

Related

Should I treat an Expo Push Notifications Token as a sensitive information? If so, how do I send notifications in a secure way?

In my app, after a user sends a message to someone, another function is triggered to notify the receiver. For that, the sender has to have the receiver's push token (front end). My question is: Is that safe? Is there a better approach?
I'm using Firebase but I couldn't figure out a way to send this notification through Google Cloud Functions...
Yes you can treat it as sensitive information. Tokens could contain information that when a malicious user accessed, it can be used to impersonate your app and send their own messages to users. While there's no reported instance (yet), it would be wise to follow the best security practices.
According to this documentation on Sending Notifications with Expo's Push API
We offer the use of an access token alongside the push token as an additional layer of security.
If you're using the expo-server-sdk-node, upgrade to at least v3.6.0 and pass your accessToken as an option in the constructor. Otherwise, pass in the header 'Authorization': 'Bearer ${accessToken}' with any requests to our push API.
Any requests sent without a valid access token after you enable push security will result in an error with code: UNAUTHORIZED.
You can check this blog on Implementing Push Notifications with Expo and Firebase Cloud Functions on how to push notifications securely.

Adding a User Sign-in for Mobile App on a serverless backend on AWS

i am creating a mobile app for multiple platforms (iOS, Android, PWA (Web)) and have my backend build with the serverless framework on AWS Lambda, using API Gateway and DynamoDb.
My most recent goal is to add a user login using AWS Cognito, enabling my users to either login using their email and password, or a facebook login. I read multiple threads, tutorials and the official AWS Documentation but am super confused because of the mass of different information.
I want to integrate authorized API Endpoints which can only be called when the user is logged in.
Therefore my first question is:
1) Should i rather use AWS Cognito User Pools or AWS Cognito Identity Pools?
I also read that for user pools you can solely use the hosted UI for login, which is not a possibility for my app. I want to style my own login page.
As i could not find any sample code for the client side integration, i went with identity Pools for now, and created an endpoint in my serverless.yml which is specified the following:
functions:
xxx-auth:
handler: endpoints/xxx-auth.execute
events:
- http:
path: xxx-auth
method: put
cors: true
integration: lambda
authorizer: aws_iam
So my second question is:
2) How do i properly integrate the authorization for my Cognito Identity Pool or User Pool?
From another Thread i read that there is the possibility to generate an SDK for the API one created on API Gateway, which handles the signature procedures of the request for you. As i tried to do so in my iOS application, i first log the user in using the following code:
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: .EUCentral1 ,
identityPoolId:"eu-central-1:XXXXXXXX" ,
identityProviderManager: CustomIdentityProvider(tokens: ["graph.facebook.com": FBSDKAccessToken.current().tokenString]))
let configuration = AWSServiceConfiguration(region: .EUCentral1, credentialsProvider: credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
and then use the following created code to submit the PUT request:
public func XXXPut() -> AWSTask<AnyObject> {
let headerParameters = [
"Content-Type": "application/json",
"Accept": "application/json",
]
let queryParameters:[String:Any] = [:]
let pathParameters:[String:Any] = [:]
return self.invokeHTTPRequest("PUT", urlString: "/XXX", pathParameters: pathParameters, queryParameters: queryParameters, headerParameters: headerParameters, body: nil, responseClass: nil)
}
But i cannot see any code that signs the HTTP request. Therefore the third question is:
3) How do i create the SDK that properly sends the signed HTTP request to my API Gateway backend?
I also tried the same for Cognito User Pools, using a simple "Authorization" header, but could not figure out a way to obtain the respective Authorization token on the iOS application without using any kind of hosted UI.
It would be very kind if someone could explain this jungle to me.
I figured it out by myself:
1) It depends. I am now using a combination of both for the following reason:
For a Facebook Login, we are using a Cognito Identity Pool, as the Cognito UserPool does not support a Facebook Login outside of the hosted UI. For Email signup and login we use a UserPool inside the Cognito Identity Pool.
2) The code snippet i posted was correct.
3) The code snippet was also correct. My mistake was that i did not correctly display and inspect the reply of my API and therefore thought the request was not authorized, but it was.

Is it ok to store user credentials in the JWT

Is it ok to store user credentials (username / password) in the JWT (so sign it and verify the resulted token later)?
I heard that
No, it is not secure to send a password in a JWT. This is because the
JWT claims are simply encoded and can easily be decoded by anyone that
sees them. It is not secure to store any sensitive information in a
JWT that returned to a user
but I don't know why does the JWT website recommends using it for authentication purposes then:
When should you use JSON Web Tokens?
Here are some scenarios where JSON Web Tokens are useful:
Authentication: This is the most common scenario for using JWT. Once
the user is logged in, each subsequent request will include the JWT,
allowing the user to access routes, services, and resources that are
permitted with that token. Single Sign On is a feature that widely
uses JWT nowadays, because of its small overhead and its ability to be
easily used across different domains
The JWT is the result of the authentication. For example
User sends his credentials (e.g. username/password) to an authentication service. It could be a third party one or one inside your monolith or your own microservices dedicated to authentication.
The service validates username-password. If authentication success it returns an JWT that represents that the user is already authenticated, in other words he is who claim he is. This JWT could contain a payload without sensitive information (don't store the password here).
The user sends another request to a service business with the JWT. If the JWT isn't expired and is not corrupted (the sign is still valid) then the service could trust in its JWT. Maybe this task will be delegated to an authorization service.
What is inside the JWT token?
Well, the simplest JWT contains information about the sign (I can't enter in much detail here because I'm not a security expert) that allows to check if the sign has been corrupted when a request with the JWT is received.
This information can be verified and trusted because it is digitally signed
Besides that, the JWT allows to send a payload.
More formally, the JWT is composed by:
Header: type of the token + hashing algorithm being used
Payload: Claims are statements about an entity (typically, the user) and additional metadata.
Signature: The signature is used to verify that the sender of the JWT is who it says it is and to ensure that the message wasn't changed along the way.
For example, if I send a request to a authentication service with my credentials username:password being gabriel:giussi, it will check these credentials and if they're OK it could create the following JWT:
Then with every request I will then the encoded JWT that contains my username and the service will
Perform authorization (What Gabriel is authorized to do?) if the JWT sign is valid.
Ask me to login again if the JWT has expired
Return an authentication error if the sign is broken.
Shortly: yes, it is OK to pass/receive sensitive data in JWT if you encrypt the data before placing into JWT's payload and decrypt it after the JWT validation to use it.
In a general case you would not need to keep user credentials in the JWT because the JWT is by itself a dynamically generated credential that represents the login / password (or the other means of authentication) provided at the JWT's first generation time.
1.1 You could however pass something that is not as sensitive as pure login / password but still bears the valuable information you need at the JWT validation time. It can be user ID (in a sub claim, hashed if desired), or access level code or the like.
Nevertheless if you wish you can pass the sensitive information with JWT. And this is all pretty easy as per below.
2.1 For sensitive data you could use your specific private claims in the JWT's payload, e.g.:
{
// These are registered claims: (see https://www.rfc-editor.org/rfc/rfc7519#section-4.1)
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
// There can be some public claims you are not afraid to expose to the world
// these are omitted here for brevity (see https://www.rfc-editor.org/rfc/rfc7519#section-4.2).
"omitted": "for brevity",
// And here can go some private claims you wish to include in the payload, e.g.:
"sensitiveInfo": {
"username": "admin",
"password": "12345",
"account_balance": 10000,
"etc": "something else"
}
}
2.2 The sensitiveInfo payload key by default is only base64-encoded (so it is easily read by anyone who gets the JWT). To make it secure you can encrypt it with some external module (e.g. crypto or bcrypt on NodeJS or PHP's techniques of your choice).
2.3 In this case:
At the JWT generation step you have to encrypt the key's data before you provide the entire payload to JWT generator.
At the JWT validation step, after the JWT successfully passes the standard validation (e.g. jsonwebtocken jwt.verify() in Node) you get the decoded payload with encrypted data in sensitiveInfo key. You now just have to decrypt the data and use it as you planned.
This is it.
You should use jwt only to store a token which your API will consume. The token will be generated after a successful login and it can be attached to any request sent to your API and all request should be proceeded only if the token is valid.

Integration of Spring Oauth2 implementation with the HTML front end using javascript

I am implementing spring oauth2 for securing my rest api. Basically i am limiting the use of rest api to particular users rather then limiting to every users.
I had implemented the backend and secured my api using spring oauth2.
I am following this steps:
1)Send the GET request with the five parameters.
localhost:8080/SpringRestSecurityOauth/oauth/token?grant_type=password&client_id=Awyi123nasdk89&client_secret=asdj39m32##$s&username=rahul#gmail&password=rahul#9831
2) Server validates the user with the help of spring security and return the json response with access code.
{
"access_token": "22cb0d50-5bb9-463d-8c4a-8ddd680f553f",
"token_type": "bearer",
"refresh_token": "7ac7940a-d29d-4a4c-9a47-25a2167c8c49",
"expires_in": 119
}
3)I access protected resources by passing this access token as a parameter, the request goes something like this:
localhost:8080/SpringRestSecurityOauth/api/users/?access_token=8c191a0f-ebe8-42cb-bc18-8e80f2c4238e
4) In case the token is expired, user needs to get a new token using its refreshing token that was accepted in step(2). A new access token request after expiration looks something like this:
localhost:8080/SpringRestSecurityOauth/oauth/token?grant_type=refresh_token&client_id=restapp&client_secret=restapp&refresh_token=7ac7940a-d29d-4a4c-9a47-25a2167c8c49
All the above step are working fine. Now i need to implement this on my client side. So that a particular client can access this call. I am using HTML/CSS as client side technology.
How client can get the access token? Should it be stored in the browser local storage? Or it should be generated every time the rest call is been made?
Any example would help me to proceed further.
I'm implementing my project like you. I use angularjs and get the access token from response json then store it into cookies.
This link provide sample code for you: http://www.baeldung.com/rest-api-spring-oauth2-angularjs. (See Frontend - Password Flow).
Because refresh token should keep secret and the client is html app, you should see this link http://www.baeldung.com/spring-security-oauth2-refresh-token-angular-js for handling refresh token.
For html client, after obtaining access token using refresh token when access token is expired, I use http-auth-interceptor ([http]://witoldsz.github.io/angular-http-auth/) to retry all rest requests failed because of expired access token.
I'm sorry that I have not enough reputation to post more than 2 links.

Getting refresh token in Android application from Spring OAuth2 based authentication server

I would like to authenticate android application using OAuth2 in my web service. After some research I know that I should use /oauth/authorize endpoint which gives me implicit authentication. However, in the end after redirection to login page and successful login, server returns access token. After it is expired user has to login again. This is a problem in my scenario and I would like to get also refresh token to be able to use it, to get access token when the old one has expired. Is such scenario possible using spring OAuth2?
In your AuthorizationServerConfiguration you should have a TokenServices bean that is implemented by DefaultTokenServices.
defaultTokenServices.setSupportRefreshToken(true); // enable refresh tokens
Then in your client configuration, be sure to set support for refresh tokens.
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("trusted-app")
.authorizedGrantTypes("password", "refresh_token")
.authorities("ROLE_TRUSTED_CLIENT")
.scopes("read", "write")
.resourceIds(resourceId)
.accessTokenValiditySeconds(accessTokenValiditySeconds)
.refreshTokenValiditySeconds(refreshTokenValiditySeconds)
.secret("secret");
}
When you request make a request to the token endpoint, it should include a refresh token.
/oauth/token?grant_type=password&username="+username+"&password="+password
This should get you a new access token
/oauth/token?grant_type=refresh_token&client_id=trusted-app&refresh_token="+refreshToken