I have a MEAN stack application that uses JWT for authentication. I use Satellizer (an Angular module) to implement the JWT authentication flow. It sends the Authorization header with the bearer token whenever requests are made through the app.
My problem is when a request to a restricted url, lets say /dashboard is made through the address bar, the browser does not send an authorization header, thus blocking the request.
So what should I do to make the browser send the authorization header when making requests to restricted urls?
If the user directly enters an address in the bar I'm afraid you can not do anything except redirect to the error form. The browser will not send specific headers
But if you are building the links that the user clicks, then you can add the JWT token in the URL link itself /dashboard?jwt=. In the server you will have to take into account this case of authentication
Be careful in this case, the browser could cache the URL and write it in some log. If the JWT is signed and not encrypted it could leak sensitive information if an attacker has read-access to the log files. Also it could be possible a session hijacking attack.
Related
I am trying various Java Spring based security implementations as follows
1. JWT Authentication
User access /
Springboot identifies as protected resource and redirects user to /login
User enters credentials and browsers does a POST to /authenticate
Server validates the credentials and generates JWT token. Set into response header and redirects to /
Browser loads /. AngularJS recognizes JWT token in the response header and stores the same in the localStorage
All subsequent calls will have the Bearer token in header (injected through httpInterceptor)
Note: Stateless Session
2. OAuth2 authentication
User access /
Springboot identifies as protected resource and redirects user to /login
/login is intercepted by Spring security. Redirects to Oauth2 authorization server with a generated state and redirect URL back to application
User enters credentials
Oauth server redirects back to application URL "/login?code=xxx&state=yyy"
/login is intercepted by Spring security. Recognizes the code and state, generates Cookie and sets in response header. Redirects to /
Browser loads /. Browser recognizes cookie in the response header and stores the same.
If a call is made to /user, the Principal object is populated with the JWT which I am able to extract as follows
#RequestMapping(value= {"/user")
public ResponseEntity<Map<String, String>> user(Principal principal) throws Exception {
OAuth2Authentication obj = (OAuth2Authentication) principal;
authentication = obj.getUserAuthentication();
OAuth2AuthenticationDetails oAuth2AuthenticationDetails = (OAuth2AuthenticationDetails) obj.getDetails();
String jwt = oAuth2AuthenticationDetails.getTokenValue();
All subsequent calls will have the Cookie in the Request
Note: A Stateful Session is created in server side to store the session details. This required to decrypt the cookie and identify the user
Now I want to implement security using Oauth2+JWT but stateless at same time as follows
3. OAuth2 + JWT + Stateless
User access /
Springboot identifies as protected resource and redirects user to /login
/login is interecepted by Spring security. Redirects to Oauth2 authorization server with a generated state and redirect URL back to application
User enters credentials
Oauth server redirects back to application URL "/login?code=xxx&state=yyy"
/login is intercepted by Spring security. Recognizes the code and state, extract JWT token by invoking
OAuth2AuthenticationDetails.getTokenValue() and set in response
header. Redirect to /
Browser loads /. AngularJS recognizes JWT token in the response header and stores the same in the localStorage
All subsequent calls will have the Bearer token in header (injected through httpInterceptor)
Question
I am trying to figure out how to implement the highlighted step above
Just an idea/direction, if I got you right:
You can create a GenericFilterBean and add that to the HttpSecurity filter chain.
When using JWT, there should be something similar (a filter, which extracts the bearer-token from the header) and then populates an Authentication object for Spring Security.
So the new filter could grab the token from the request and set the response accordingly.
You could also handle that in an unprotected (!) callback endpoint like login/callback?..., which than sets the cookie for you.
In our application, the server (spring boot) is totally stateless and does not have any oauth nor stateful stuff. Obviously it never redirects anything or has any other views/endpoints than / for AngularJS (and some REST-APIs under /api/...). Thus, the OAuth-flow is totally handled by AngularJS, which in turn checks the callback from the oauth-server and locally sets the JWT-Token (like in your first approach). In first versions we also tried to mix up redirects with stateless JWT and stateful sessions etc., but this led to very strange behavior with the logins - the state (logged in or not) was not always clear and in some cases redirects were wrong etc.
This might help you implement your desired solution.
The author proposes that once a user successfully authenticates with Oauth2 providers (Google etc), you send a short-lived token as a URL param to your frontend application and use this short-lived token to exchange it for a longer-lived token.
I have a website that runs on example.com. The website makes AJAX calls to my backend API which sits at api.example.com.
I employ a double-submit verification strategy for my authentication.
The backend has protected endpoints which check the JWT token with each request. The JWT token is stored in a httpOnly cookie. It also contains the CSRF token.
Alongside the JWT cookie I also send a CSRF cookie which is not httpOnly.
Each request that the client makes must contain the value of this cookie in a special header.
So far so good, but, I want to make sure that the client does everything in its power to prevent users from making pointless unauthenticated requests. So in my React app I have declared a few private routes which check if the user is logged in and if they are not, the user is redirected to the login page. The logged-in state is kept in the Redux store.
The issue is that on a full refresh the Redux store is reset. So as I see it, my options are:
Option 1) Check the existence of a CSRF cookie
The way I check if a user is authenticated is by checking if they have the CSRF cookie; I also do this during the store initialisation. If they do have the cookie, they are allowed to navigate to the protected page. All subsequent requests on this page are still verified on the backend for a JWT and CSRF token.
Option 2) Check against the backend each time
I can create a simple endpoint on the backend that is used to check if the user is logged in. So instead of just checking the cookie, the client can submit a request to this endpoint and verify that the token in the cookie is still valid.
Option 3) Persist the Redux store
I could implement a persisted store (there are some libraries that do this out there) so that the initial problem is automatically resolved, i.e.: the logged-in state is preserved upon full refresh. However, this yields a bunch of issues with caching and token expiration and it may not be worth the effort.
I route a user to another web site from my Angular application using $window.open(url, ''). Currently they are directed to the login page but now there is a requirement for single sign on so the user can access the external site if they are logged in to my application. The external site has asked that I send a JavaScript Web Token in the Authorisation Header using the Bearer schema when I redirect the user.
How can I set the Authorization header in Angular when sending a user to anther site. I've only ever used the header in the context of communicating with an API ($http.get()), rather than sending the user elsewhere. I don't think $window.open has any means to do this so I might need to use something else.
Although this question is similar, the answer describes sending the token as a get parameter in the URL. The Authorization header is not used. how to add authentication header to $window.open
I am having troubles in implementing OAuth in the right way.
I use a client/API architecture (Angular for front and Node.js for back) and I would like user to sign in using Google OAuth authentication only.
Here is what I think is the right way for the moment (tell me if I misunderstood something) :
Angular open a Google popup asking user's consent.
Once the user agree, Google Authorization server sends back to angular a verification code.
This verification code is forwarded to an API endpoint.
Then, the API asks Google Authorization server to exchange this code for an access_token, an id_token and a refresh_token.
Google sends those 3 tokens.
The API uses access_token to retrieve user from Google API
The API persists the user
Here is the little dillema, in my opinion, the access_token and refresh_token should be stored into the database and the id_token should be sent back to Angular client.
This way, it would allow the API to ask for resource in Google API and if the token expires it can still ask for a new token thanks to the refresh_token.
Client-side, the id_token is embedded in all requests thus allowing the API to identify the client and verify his authentication with Google certs from https://www.googleapis.com/oauth2/v3/certs.
Supposing this is right way to use tokens, how could I deal with id_token expiration since client does not have any refresh token ?
Thanks !
I do it slightly different (I have the same basic architecture though).
Angular decides the user needs to log in and displays a login popup.
The url in the login popup is not serviced by angular, but is instead directly run off of the backend server: /auth/google . (I use hapijs and bell, personally).
/auth/google is serviced by a bell plugin and initiates the OAUTH dance.
the end of the OAUTH dance results in my node server generating a local token (I just generate random bytes and store them in redis mapped to user ids)
because the initial login popup was created by window.open, the success page (generated on the api side rather than in angular) can use window.opener.postMessage to communicate the token back to the angular runtime.
This way, all my sensitive google credentials (the user's oauth token, refresh token if needed, and my application's api ID and secret) are only on the server, except for during the OAUTH dance relay when they're in a URL string during the client redirects. This is reasonably secure.
Then for all the actual user interactions with the api, I use the token I generated in step four to authenticate. This could be a JWT if you wanted, but I don't do it that way; I just use redis to map from 'longrandostring' -> userId. That lets me (for example) force everyone to re-login if I wipe the redis database that has all the tokens stored, or I can write a lua script to delete all the entries that map to a certain userid.
If you need a refresh token, you can set access_type=offline in the initial request to oauth2/auth, and you'll get a refresh token as part of the response, unless you've previously gotten a refresh token. You can then persist it on the server side and get new access tokens as needed. If you set approval_prompt=force as well, you'll force a new consent screen and be guaranteed a refresh token (but after some small number of refresh tokens granted to a user, older ones expire on the same application so it's best to only request them if really needed).
I've run into an issue when using OAuth 2 authorization codes in an web app's URL, such as is returned by Google's OAuth method (https://developers.google.com/accounts/docs/OAuth2Login).
I've been using the google redirect method; where you redirect the user to a Google URL, passing in client_id and redirect_uri. The user authenticates and the authorization code is passed to the redirect_uri as a
The issue is that the access code stays in the page URL, so if the user bookmarks or posts the URL, they are sending an invalid Authorization Code.
Eg:
http://myapp.com/?code=kACASDSDdAS81J5B8M_owCyUNgV46XdZaqBBMh4T8OJFEKPRrgN7gtiFOcMW5Fv3gk
What is the best way to handle this case? Ideally, I would like to send the authorization code in a POST body as it isn't visible to the player?
I've spent a bit of time looking at Google App Engine (the platform I'm using) to redirect the user, but can't seem to send a POST body in a redirect.
After the user is directed to your app with the authorization code in the URL query parameter, you should:
1) Exchange the authorization code for an access token by making a HTTPs POST to Google's OAuth 2.0 token endpoint and save that access token as appropriate (datastore, memcache, etc)
2) Redirect the user to a URL without the ?code. You can't send a POST body in a redirect (HTTP doesn't allow it), but that shouldn't be necessary if you store the access token server-side for making API calls.
If you must make the token accessible client-side, you can:
a) Send it back as a cookie along with the redirect (which exposes it to the client, though you could encrypt it) OR
b) Generate a HTML form, with JavaScript for auto-submitting it instead of doing the redirect. Kind of ugly, but common.