I have a scenario where login and logout API's from third party service provider. Redirection to the above API's call happens in my web layer(using Spring) based on the available cookies and using Angularjs as front end.
Coming to my question, How can I redirect to previous Angular state after log-on into my application once user hits logout.
You can go about this two ways that I can think of. If the data is simple enough, you can add it to the url as a query parameter. If it is more involved, then you may want to look into using local storage. You can save the state to local storage, and then retrieve it when you get redirected back into the app. There are some edge cases you will have to consider, but that should work for you.
Related
We're currently evaluating Keycloak as our SSO solution and while it works for our servlet-based applications there's a question regarding our (React-based) SPAs.
What our designers want: as an example let's say we have an email client spa. The user is in the process of writing an email but then gets distracted. When he returns the SSO session has already timed out and a re-login is required. The user should now be presented with a login form and after login it should be possible to send the email that's still in the SPA's local storage (i.e. re-login without restarting the SPA or losing data).
AFAIK Keycloak doesn't provide an authentication-api (for good reasons) and uses a redirect to the login page and back to the application (as I understand it for mobile apps the system browser would be used). If I'm not mistaken that redirect would then mean the SPA is then reinitialized and thus the data would be lost.
So here's the question: is what our designers want possible to do with Keycloak?
If yes, how would it be done? Directly posting to the login-url that Keycloak is using seems like a bad idea since the tokens would probably not be stored correctly and there might be same-origin policy problems. Would doing it inside an iframe or popup-window work?
For someone who comes back to this question,
I think it's better to stick to the best practice for oAuth2/OpenId Connect for SPAs which is currently "Authorization Code Flow" with PKCE.
https://oauth.net/2/pkce/
https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics-13
A normal flow here needs a complete redirect to the auth server and back so your app will completely re-initialize. Or you use check-sso like Sébastien already mentioned with silent mode.
https://github.com/keycloak/keycloak-documentation/blob/master/securing_apps/topics/oidc/javascript-adapter.adoc
You can configure a silent check-sso option. With this feature enabled, your browser won’t do a full redirect to the {project_name} server and back to your application, but this action will be performed in a hidden iframe, so your application resources only need to be loaded and parsed once by the browser when the app is initialized and not again after the redirect back from {project_name} to your app. This is particularly useful in case of SPAs (Single Page Applications).
This way the login will happen in an iframe and the app initializes only once and should preserve state.
Even if it's not considered as a best practice you can turn on Direct Grant Access for your client which enables to login through a REST call.
Anyway, about not loosing the state of your app, this is a bit outside the scope of Keycloak but you should be able to achieve that with having the state in your redirect URL for instance ?
Also, if you don't want your app to automatically reidrects to the login page you can use : keycloak.init({ onLoad: 'check-sso' }) instead of login-required
I have a mobile website written in angularjs, with my backend in Spring Boot. Right now, I have my own login page and can login a user without any trouble. However, if the user ever clicks "back", "refresh", etc., the client loses the user's id and login info (obtained from server on login). I need to make sure that this info is maintained and clicking "back" or "refresh" doesn't break everything.
Secondly, a user that knows the url's after login can type those url's in the browser and access them without logging in. I can stop them accessing anything on the server, but not sure what I can do on the client to redirect them to a login page in this case.
Any help would be greatly appreciated!
You should keep in mind that everything running in browser is stateless, there's no way to keep trace of the previous state.
Right now, if the user performs a refresh (or another similar action), Angular loses everything (AuthData included).
You have many way to work around that limit:
Perform an http request after the application bootstrap (have a look at the angular.module().run method
Save a cookie and use the server to print initial data layer directly on the dom via json
Save on local/session storage
Personally, I prefer cookies because that lets the server to work decoupled from the client.
In reference to your comment..."if the user ever clicks "back", "refresh", etc., the client loses the user's id and login info (obtained from server on login)."
Is there any reason you need to maintain the user id or login info after a successful authentication?
If Spring Security is setup for basic authentication, after a successful login, a Session Cookie will be sent back on the response to the client. On all subsequent requests to the server, the same Session Cookie will be sent on the request and the previously authenticated session will be re-established. You just need to ensure that your Angular client is passing cookies when issuing requests.
Take a look at this sample on how this is done.
I'm using Laravel 5 with AngularJS for a project, in a way so that Laravel is used as an API and the API routes are in Laravel, while the client side routes are in AngularJS (app.js).
Is it possible to use Laravel Middleware to protect AngularJS routes, so for example, I want it to use the RedirectIfAuthenticated Middleware on the angular login form page route so people can't go to that page if they are logged in, except normally as far as I know, the middleware is specified in the Laravel controller, which doesn't have logic for angular side routes - hence, the problem.
So the question is, can I use Middleware or do I have to make angular send a get request asking laravel if the user is logged in on every page? Wouldn't that be less secure?
What I ended up doing was making a client-side cookie on login in angular to keep track of whether the user is logged in or not for user experience purposes (hiding information, redirecting before the view is rendered), and using Laravel Middleware to protect API calls to make sure the user can't interact or get information from the API on the server and to keep it secure in case the user changes their cookie to lie about their login status.
Alternatively, you could also send a request to the server before each page loads instead of the cookie check, but that adds quite a bit more overhead, and isn't any more secure - as far as I know, since that API call to check if the user is logged in is just for UX purposes too and the javascript for that can be removed by a malicious user.
We have an app which which has various different pages which require authentication; this auth uses Google's oAuth2 flow and is currently working correctly apart from one thing: after we receive the callback from Google at our callback endpoint, we have no way of knowing where to redirect the user after success as we have no idea which page they were on when they first started the auth process.
What happens instead is that we redirect to the same page for all successful requests; this is jarring to the user as they've likely landed on a page they did not request and have to navigate back to the section they desired.
I can't find anybody talking about how to do this and all the Google samples simply do what we do and redirect the user to a standard URL.
We've tried url-encoding the redirect we want as a query parameter on the callback URL we pass to Google initially but this fails as the URL no longer exactly matches the 'allowed' one we have set up in the Google APIs console (and there is only one box to add one).
Obviously our callback method would check any data returned from them before redirecting the user (i.e make sure it's a valid place to redirect the user to) - so, is there any safe way of doing this? Ideally without having to put the URL on the session..
Thanks in advance!
The official technique is to set the state parameter which is returned to the callback url
You can redirect your user to a page with a javascript function to read in the localcache the last url visited before authentication.
You can also use a cookies for that.
This solution can be coupled with a breadcrumb widget on your website.
You can store the fromUrl into the memcache and redirect on this url when you OAuth workflow is completed.
If the memcache value has been unset, redirect to the home page.
I'm developing an AngularJS app used by third part applications. The third part application and my AngularJS application have a common database where users preferences/credentials are stored. User can login from the third part application and, by redirecting the user into my application, I need to maintain the user logged in, without asking a new authentication procedure.
I can't use cookies because the two applications are in two different domains.
I can't pass a session TOKEN (correspondant to the user logged iin) in query parameters due to man in the middle risks.
Is it possible to make a POST request to an angularJS page? Third part app call my AngularJS login page POSTing a token in the body request. My app take the token, verifyies it and log-in the user.
Constraints:
App in different domains;
Maintain user logged in;
No sharing cookies;
Try to prevent man in the middle;
No query parameters;
HTTPS protocol;
web based applications.
Am I missing something in the https protocols/sharing sessions?
Are there other solutions supported by AngularJS?
How can I redirect the user from one application to another and maintaining the user logged in in a simple way? Is there a simple flow I haven't figured out?
AngularJS is based on REST api communications. I can ask for a webpage (GET the webpage), but I can't make a POST to an AngularJS page. Is there a way to pass/share some values from the first application to my second app in a secure way?