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.
Related
As we know Rest services are stateless, General strategies to authenticate is using a token based authentication.
In login service it takes credentials which returns a token.
This token might be set in client cookies, and all subsequent requests uses this token to be validated and process new request if token is valid.
Now my question is how one can validate the token ? If someone has stolen the token and tries to access rest services with stolen token by just editing cookies then how can it be identified and restricted ?
We can never know if the token is fetched by valid user and same user is trying to access subsequent request. but what are the possible ways to make it more hard, like to verify if the request has came from same source ?
One general suggestion is to set aging for token/cookies, but it still not helpful till the age of that token/cookies.
Any suggestions would be appreciated.
I don’t believe there are any 100% fool proof methods of preventing access with stolen user tokens. How do you even know that the token is stolen in the first place? But from the top of my head you might want to consider following:
Accessing a REST service with the same token but a different user agent is suspicious. This can be recognized with the value of the User-Agent header. You might want to consider dropping such requests.
What if the IP address changes but the token is still the same? Well, maybe someone is using a load balancer and accesses the network over different IP addresses? Or he accessed a VPN with the same token/cookie as before? If you have no compunction dropping such requests, you might level up the security by checking the source IP address too.
In case of – say – JWT tokens, you will need a bit of infrastructure to handle the blacklisting. Follow this.
My current understand of the "most secure" approach to authorizing requests in the browser is to require validation of an HttpOnly SameSite cookie AND HTTP header (e.g. Authorization or X-CSRF-Token) in combination.
For example, when issuing the JWT to a browser, send the JWT signature in an HttpOnly SameSite cookie, and send the body (without signature) to the client to store in localStorage and submit in the Authorization header. When authorizing a request, combine the two back into the complete JWT and validate it as normal after that.
Alternatively, you can generate two JWTs with a field to distinguish them (e.g. the client one has "browser" in it, the cookie has "cookie") and require that both are valid and both identify the same user. One is sent in the Authorization header and stored in localStorage and the other uses the SameSite HttpOnly cookie.
Another popular approach is to store a CSRF token in a field in the JWT, and put the JWT into a cookie and require the client to send a matching token in a header (e.g. X-CSRF-Token).
All of the solutions effectively prevent XSS and CSRF attacks: XSS cannot retrieve the HttpOnly cookie, and CSRF does not include the HTTP header, so this blocks both attacks.
Note that you probably only want to apply this rule for requests from web browsers. For server-to-server communication, requests are not subject to CSRF and XSS attacks.
After struggling through various approach We found a solution explained below:
We store token (encrypted) in cookies on login request and for each subsequent request this cookie gets validated.
The problem was if someone replace the token in cookie with another valid token, as cookies are maintained by client browser.
Solution :-> Though token values were encrypted, it was representing only one value, So if one replace whole encrypted value with another valid encrypted value it can be hacked.
So to solve this we have added another cookie which was combination of multiple values.
e.g.
Cookie 1 -> encrypted token
Cookie 2 -> An encrypted object containing information like username+ some other user context details+token
So in case of Cookie 1, it was easy to replace with another encrypted value as it was representing only one token though it was encrypted.
But in case of Cookie 2, it was containing object with multiple values, so only token value can not be modified, encrypted and set back in same cookie.
Before authentication We are doing decryption whole cookie 2, fetch token part from it and validate the token part of it against cookie 1.
That has solved our problem !!
Thanks all for your time and guidance.
You can use jwt is an Internet standard for creating JSON-based access tokens that assert some number of claims. For example, a server could generate a token that has the claim "logged in as admin" and provide that to a client. The client could then use that token to prove that it is logged in as admin .
How it's working ?
First it's contain private key generated by developer :
let us have this key :sfcqw#sav%$#fvcxv*s_s515 and this one called private key , and we also have a public key this the public key generated depended on user data and private key and it's impossible to know what is contain if you don't know the private key .
to more explain :
public key :
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.plpJkAcgrgCIsoRyV2kjGsvWF6OsXU1mD785OSWTH4o
we have the above key generated by our private key : sfcqw#sav%$#fvcxv*s_s515
To be more clear going to this website : https://jwt.io/ and try to past the public key without put secrite key like picture and you will understand everything .
To me, there was no way to prevent the access from being stolen JWT token except
setting a short timeout for the token
more secured at the HTTP request level by only allowing specific `User-Agent. See more
more secured at the HTTP request level by customizing the header key for the organization, e.g My-X-Auth = Bearer <token> instead of Authorization= Bearer <token>
more secured at the HTTP request level by restricting trusted urls/domains, e.g X-Content-Security-Policy. See more
I have some questions regarding an API JWT refresh token workflow using Java Spring.
I have this so far:
User logs in to /users/login - if successful a response with 2 headers is returned Authorization and Refresh. Which contain 2 tokens - one with short 30 mins expiration and one with longer 4 hours expiration.
He can then access all other endpoints using the Authorization header.
If at some point accessing an endpoint his token is expired he receives an error (UNAUTHORIZED).
And has to do a request to /token/refresh with the refresh token he was given.
Questions:
I have set it up so authorization token has a claim: type=auth and
the refresh token has a claim: type=refresh. What is the best way to
distinguish the two tokens.
What should be the error in step 3 (instead of unauthorized) to distinguish it from a request without a valid token
/token/refresh doesn't ask for authentication currently. Should it?
Should the /token/refresh endpoint be a POST with header, POST with parameters or a GET with header.
What is the best way to distinguish the two tokens.
Refresh token does not have to be a JWT at all. I prefer to simply generate a random alphanumeric string. Refresh token does not carry any additional information. It requires a lookup to database to confirm validity of refresh token. You distinguish them by where they appear in your request. Authorization token (access token) should appear in a header of your choice.
What should be the error in step 3 (instead of unauthorized) to distinguish it from a request without a valid token
Sending 401 Unauthorized is exactly the way to do it. 401 tells the client, that he cannot access the resource now, but he can take actions so that he can access the resource again (login/refresh token). 403 on the other side would tell the client, that the resource does not belong to him and he will have to ask for permissions, e.g. by contacting an admin
/token/refresh doesn't ask for authentication currently. Should it?
No, there is no need for authentication.
Should the /token/refresh endpoint be a POST with header, POST with parameters or a GET with header.
Generally a GET endpoint should be read only and not mutate any resources. POST and PUT endpoints are intended for mutations. In this, I'd use a POST with parameters and a dedicated URL, e.g. /token/refresh
Current Scenario
A Spring project have REST API's protected using Spring Security and JWT. These API's produces JSON response. A UsernamePasswordAuthenticationFilter is implemented for validating JWT sent in Authorization header. Both authenticated and unauthenticated API's are working as intended.
Requirement
Now I need to sent an image in HTTP response for logged in user.
Solution1
Sent a byte[], representing the image as the value to an "image" key along with other information.
But, this may take some time for the full JSON response, if the image is large.
Solution2
Sent a link as the value to an "image" key along with other information. The client can assign <img src=the_link>, which will supposed to fetch the large image in a separate request. Then create a request with #RequestMapping, corresponding to that link, which produces a byte[].
My Problem
I prefer Solution2. But it will produce UNAUTHORIZED exception as there is no valid Authorization token. Also, this API must be authenticated.
After some search, found out this, which is the same as my requirement. The accepted answer says,
The OAuth Bearer Token spec supports sending the token as a query parameter.
Is this what I must do?
In my Spring filter, get JWT from Authorization header, if it is
empty, get it from request.getParameter()
In JSON response of first
API, send "image":"http://ip/getImage?token=dbscsbCXV"
Create an API #GetMapping("getImage") byte[] getImage()
Or is there any better approach?
Please guide me.
Your suggestion to include the token in seems to be okay, if you:
Use HTTPS for your server, otherwise the JWT token in the request headers are expose (same goes for the Authorization headers).
Don't mind the image URL no longer working, when the token changes
Another approach may be to generate a random key with sufficient entropy (eg. combine 3 UUID's into a single string) and store this along with your Image entity, returning it from your REST services, eg:
https://ip/images/824b6854-edcc-11e6-bc64-92361f0026713567fef0-549a-4cdb-9264-5e15166dfd6f/the-file-name.pdf
Make sure you disable the Spring security filter for these "public" paths.
Advantages of this approach:
No need to check authentication for this resource
(if the image doesn't change alot) You can have this cached or serve the content through CDN, not hitting your servers every time for just streaming images.
URL will keep working, even if JWT token for auth changes
You might think this is less secure than the using a per-call authentication, but if the ID's have enough entropy, it's waterproof. Facebook also uses this concept (https://www.quora.com/Are-Facebook-pictures-really-private-and-are-they-hosted-on-Facebook-servers, https://en.wikipedia.org/wiki/Capability-based_security)
I get a valid code on the client side login of my application using angularJS Oauth Module GAuth.checkAuth(). and then GAuth.getToken().
The code is valid only for 1 hour and any API like GoogleDocs,Gmail accessed after 1 hour fails and needs relogin.
To overcome this I am trying to send the code to the server for getting AccessCode at Server so that I can send same with requests to GoogleDocs, Gmail etc
GoogleAuthorizationCodeTokenRequest req =
new GoogleAuthorizationCodeTokenRequest(
new NetHttpTransport(),
JacksonFactory.getDefaultInstance(),
"https://www.googleapis.com/oauth2/v4/token",
// "https://accounts.google.com/o/oauth2/token",
"901142925530-21ia7dqnsdsdsndnsnnnfdc9cm2u07.apps.googleusercontent.com",
"6NSvw0efghyuuG8YGOBWPln79n",
authCode,
"http://localhost:8080");
req.setGrantType("authorization_code");
//req.put("refresh_token", authCode);
//req.put("access_type", "offline");
GoogleTokenResponse tokenResponse =
req.execute();
tokenResponse.getAccessToken()
Where authCode is the code I received in GAuth Token
But the call is failing and in response I get
400 Bad Request
{
"error" : "invalid_grant",
"error_description" : "Incorrect token type."
}
Any help is highly appreciated!
When the user first authenticates your application you are given an authorization code. You then need to take this authorization code and exchange it for an access token and a refresh token. Once the authorization code has been used it can not be used again.
grant_type=authorization_code
Denotes that you are asking Google to verifiy that your authorization code and give you a new access token and refresh token.
It sound to me like you are taking either the access token returned from that request and sending it to grant_type=authorization_code end point which is not going to work its the wrong type of code. hens the error you are getting of
400 Bad Request { "error" : "invalid_grant", "error_description" : "Incorrect token type." }
You will need to take the refresh token you are given. If there is one I am not sure that you can even get a refresh token from AngularJs. You can get one using java though.
A refresh of an access token in pure rest will look like this
https://accounts.google.com/o/oauth2/token
client_id={ClientId}.apps.googleusercontent.com&client_secret={ClientSecret}&refresh_token=1/ffYmfI0sjR54Ft9oupubLzrJhD1hZS5tWQcyAvNECCA&grant_type=refresh_token
Note the &grant_type=refresh_token. If you are using the Google api java client library it should handle all of that for you. However your tagging is a little confusing its unclear if you are trying to do this in java or angularjs which I do not believe will allow you to use refresh tokens. Again I am not an angular dev I could be wrong on that point.
Anwser:
You the code you are sending is not an authorization code. Only an authorization code can be sent to grant_type=authorization_code. Solution: Send an authorization_code
Types of Google codes and tokens:
There are three types of codes or tokens you should be aware of with Oauth2.
Authorization code.
Refresh token
Access token
When you request access of a user and they grant your application access you are given an Authorization code. The Authorization code is short lived it probably less then 10 minutes and it can only be used once.
The Authorization code is used to get the initial access token and the refresh token from googles authentication server. by using the grant_type=authorization_code
Access token are good for about an hour. They are used to make calls to google APIs
https://www.googleapis.com/plus/v1/people/me?access_token={your access token}
You can use the access token as often as you want during that hour assuming you don't blow out some quota.
Refresh tokens are used to request a new access token from the Google authentication server when the access token you have current has expired or you just want a new one. here the grant_type=refresh_token is used to request a new access token you are essentially telling google I am sending you a refresh token you know what to do.
additional reading
I have a coupe of tutorials that might help you out Google 3 Legged OAuth2 Flow and Google Developer Console Oauth2 credentials
Also helpful when learning Oauth: The OAuth 2.0 Authorization Framework
I am trying to use txtwire (for sending SMS) and they provide a httppost service mentioned below. I know it is "https" but still.. is it OK to pass my API key, userName & Password in the URL?
There is no Basic Auth Mechanism because service expects everything in URL.
https://api.txtwire.com/httppost?phone=18885554433,18885554422&username={username}&password={password}&api_key={api_key}&code=12345&keyword={Group Keyword}&message=testMessage
My only other option is to user their SOAP web service. which is cumbersome and i would prefer RESTful. would SOAP be better if passing credentials in URL is not preferred?
Here is the API : https://api.txtwire.com/documentation/class_w_s___message.html#a99faeee5de80610649b184f180098982
will appreciate any help.
Is it permitted? Well, this is a question that API service provider should answer. It looks like that textWire API doesn't have any issue with it.
For the sake of security, personally, I don't like to post/get credentials without being encrypted. Even with Basic Authorization, there is a way to add encrypted username and password as request header "Authorization". Something similar to the following:
headers['Authorization'] = 'Basic '+ <encoded Base 64 String (username + password)>
Perhaps you want to find out if textWire API support such approach.
You should be ok for both of them, from what I can see they're using an SSL+TLS certificate.
From a more technical point of view, passing the password as part of the query string (RESTful), passing it in the request body (SOAP) or passing it as a request header is actually the same approach (don't forget that basic authentication trasmits the credentials as username:password sequence encoded with base64), because the password itself is being transmitted along with the message itself.
It's a possibile practice, but I would not raccomend it. If I were to expose an authenticated service I would use a username+HMAC signature combination, or maybe an autentication token of some sort.