Disable login route if a user is logged in with Hapi.js - hapi.js

Basically I have a login/register landing page of my app. After a user logs in or registers I don't want them to be able to access this route anymore. I'm not sure how to achieve this with Hapi.js. The login page doesn't use any auth strategies so it has no idea if a user is logged in or not.

The approach I normally use for this is not disabling the route per se, but redirecting logged-in users away from the login route.
As you point out correctly your login route currently doesn't know whether a user is logged in if it has no auth strategy configured. The solution is to add an auth strategy to the login route, but using the try mode. This means the handler will be executed regardless of whether auth was successful. The trick is that you can then check if the user is authenticated (by inspecting the value of request.auth.isAuthenticated) or not and react accordingly.
So your route might look like this:
server.route({
config: {
auth: {
strategy: 'session',
mode: 'try'
}
},
method: 'GET',
path: '/login',
handler: function (request, reply) {
if (request.auth.isAuthenticated) {
return reply.redirect('/'); // user is logged-in send 'em away
}
return reply.view('login'); // do the login thing
}
});
Another approach with the same result is to set your auth strategy on try mode as the default for all routes:
server.auth.strategy('session', 'cookie', 'try', {
password: 'password-that-is-longer-than-32-chars',
isSecure: true
});
Notice that third argument try. With this approach you don't need to add any auth config to the route itself because it will try this strategy by default. According to the server.auth.strategy docs:
mode - if true, the scheme is automatically assigned as a required strategy to any route without an auth config. Can only be assigned to a single server strategy. Value must be true (which is the same as 'required') or a valid authentication mode ('required', 'optional', 'try'). Defaults to false.
There's some more info about modes in the Authentication tutorial on the hapi site.

Related

cy.origin redirects user to a blank page

Scenario:
I am clicking a login button from my application served on localhost.
It redirects me to azure sso login through cy.origin
Authentication is performed fine.
User logs in successfully to the app.
But it redirects me to a blank page and hence rest of the IT blocks get failed.
The code attached below works fine but as soon as first IT block passes, upon the execution of second IT block page is set to about:blank so the test cases fail.
Question: What should be the workaround so that I can continue testing on application under test?
Second describe gets failed
Cypress.Commands.add('authenticate', () =>{
cy.visit('http://localhost:8080/')
cy.get('input[value="***"]').click();
cy.origin(`https://login.microsoftonline.com/`, () => {
cy.wait(3000)
cy.get('#i0116').type('username')
cy.get('#idSIButton9').click()
cy.wait(3000)
cy.get('#i0118').type('password')
cy.wait(2000)
cy.get('#idSIButton9').click()
cy.wait(2000)
cy.get('#idSIButton9').click();
})
cy.wait(6000)
cy.url().should('contain', 'Welcome')
})
According to the documentation, that behavior is by design
Take a look at cy.origin()
The cy.origin() command is currently experimental and can be enabled by setting the experimentalSessionAndOrigin flag to true in the Cypress config.
Enabling this flag does the following:
It adds the following new behaviors (that will be the default in a future major version release of Cypress) at the beginning of each test:
The page is cleared (by setting it to about:blank).
If by "Second describe gets failed" you mean the second test is not visiting the Welcome page, then just explicitly visit cy.visit('http://localhost:8080/') at the beginning of the second test.
This is the recommended approach when using cy.origin.
By the way, you should set http://localhost:8080/ as baseUrl in configuration, and use cy.visit('/') instead - from Cypress best practices.
Cypress.Commands.add("session_thing", (email, password) => {
cy.session([email, password], () => {
cy.visit('http://localhost:8080/AdminWebapp/Welcome.html')
cy.get('input[value="Log In With Office 365"]').click();
cy.origin(
`https://login.microsoftonline.com/`,
{ args: [email, password] },
([email, password]) => {
cy.wait(3000)
cy.get('#i0116').type(email)
cy.get('#idSIButton9').click()
cy.wait(3000)
cy.get('#i0118').type(password)
cy.wait(2000)
cy.get('#idSIButton9').click()
cy.wait(2000)
cy.get('#idSIButton9').click();
}
);
cy.url().should('contain', 'Welcome')
});
});
The desired behavior was achieved with above code. It restores the session in beforeEach hook. I am simply calling the cy.visit('/') in every IT block and perform the required actions which is kind of very fast with session feature.

Force user to a page after sign-in and user that already log-in before

I currently have a service authentication up and running (using jwt to auth).
I'm working on a quiz service that force user to create some required information and force them to take a quiz to understand how to use our tool.
Because lacking of Frontend exp, I'm wondering how this quiz service will integrate with the auth service
Right now, for Backend side during auth service I will give them back the permission in the token if I call the function to check if the user pass the test & have a profile created. Otherwise I give them back the token with permission = []
But for the Frontend side, what is the solution to re-direct use to Quiz page (after sign-in and what about user that already log-in before)
check this documentation programatic navigation
once authenticated redirect the user back using [vue2 code]
this.$router.push({name:'Quiz',params:{id:this.$route.query.next})
In the authentication page you may pass the quiz link as next query parameter eg
example.com/login?next=< quizID >
Navigation guard documentation
You can use route guards to redirect unauthenticated users to the login page, do remember to pass the quiz id as a query parameter.
your guard will be similar to this
router.beforeEach((to, from, next) => {
if (to.name === 'Quiz' && !isAuthenticated) next({ name: 'Login', query: { next: to.params.quizID }})
else next()
})
This was assuming you have set your routes has a route named Quiz and takes :id and a route named login, similar to this.
{
path: '/quiz/:id',
name: 'Quiz',
.....
},
{
path: '/login',
name: 'Login',
......
},
Alternatively, you could have set up a dialog box on the quiz page that handles authication.

Vue-Router: Protecting private routes with authentication the right way

I have a /profile route that should only be accessible by an authenticated user. From research, the recommended approach is to use vue-router's navigation guard:
Here is the route object:
{
path: '/profile',
name: 'MyProfile',
component: () => import('#/views/Profile.vue'),
meta: { requiresAuth: true }
},
And here is the router's navigation guard:
router.beforeEach((to, from, next) => {
if (to.matched.some((record) => record.meta.requiresAuth)) {
if (isAuthenticated()) {
next()
}
else {
alert('Auth required!')
next('/login')
}
}
})
The isAuthenticated() function above sends a jwt token (stored in cookie) to the /jwt/validate endpoint which validates the token and returns a 200 OK response:
export function isAuthenticated() {
axios.post(`${baseUrl}/token/validate`, {}, { withCredentials: true })
.then(resp => resp.statusText == 'OK')
.catch(err => false)
}
With this approach, every time we visit the /profile route, we are making a POST request to the /token/validate endpoint. And this works quite well. However, is it too excessive to make this request every time?
My Solutions
I wonder if there is some way to store the data locally in memory. I thought of two possible solutions:
Option 1: Storing the data on vuex store, however I have learned that the vuex store object is accessible via the browser's console. This means that anyone can modify the access logic to gain access to protected routes.
Option 2: Store it inside a custom Vue.prototype.$user object, however this is similarly accessible via console and therefore has the same security risk as option 1.
Essentially, my question is: is there an option to access a protected route without having to validate the jwt token on the server-side every time?
You should query the server for if the token is valid once when the user initially loads the application. After that, there is usually no reason to check again. If the session expires on the server, then any other API calls you do should return a 401 response (or any other way that you choose to return an error) and your application can act on that.and your application can act on that.
If your profile route is getting data from the server to display and the server is properly validating the user for that request, then it doesn't matter if the user tries to manipulate the Vuex store or Vue state because they won't be able to load the data.
Doing authentication in the vue router is really more for convenience than for actual security.
Don't waste time trying to prevent a malicious user from exploring the Vue application - that is guaranteed to be a losing battle since all of the code is loaded into the browser.
If you really insist on some kind of protection, you can split the application using webpack chunks that are loaded dynamically and configure your web server to only serve those chunks to properly authenticated and authorize users. That said, I would expect such configuration to be difficult and error prone, and I don't recommend it.

How to assign a middleware to specific group of routes?

let's say I had this block of route, so far I only knew that middleware could be assigned through nuxt-config.js (globally) or per route (independently)
pages
- index.vue
- goSomeWhere.vue
- goThisWay.vue
- admin
- index.vue
- goThere.vue
- goHere.vue
I want to assign a middleware just for every /admin routes, so is there another approach that might be suitable for me?
Certainly the most concise way to verify a block of routes is to use a global middleware that targets any route starting with /admin.
You could set up a file inside the middleware folder that defines the redirects you need depending on the conditions. Obviously you want to block any admin route from someone who isn't logged in as an admin level user. To do this you should set any admin user in your store with a property such as "admin" or if you need to set levels you could assign a value of admin1, admin2 etc. For the sake of simplicity lets say any authorized user who logs in has a property admin = true; set in their user object in the store.
You should then create a file in the middleware folder, let's call it 'auth.js':
export default function ({store, redirect, route}) {
const userIsAdmin = !!store.state.user.admin;
const urlRequiresAuth = /^\/admin(\/|$)/.test(route.fullPath)
if (urlRequiresAuth && !userIsAdmin) {
return redirect('/')
}
return Promise.resolve
}
This simply checks if the user has admin set to true and if the requested route requires auth. It will redirect to your index page if the user is not authorized.
You will need to register your middleware file in nuxt.config.js:
...
router: {
middleware: ['auth'];
},
...
And you should be good to go.

preventing user to go back once logged out in laravel 5

I have a logout function like this
public function logout() {
Auth::logout(); // logout user
return Redirect::to('login'); //redirect back to login
}
When logout function is triggered through routes which looks like
Route::get('logout', array(
'uses' => 'userController#logout'
));
user get redirected to the login page. But when goes back using browser, dashboard view gets opened which i don't want to. What can be the best way to prevent users from going back to dashboard once they logged out? Though there are some discussion on this topic, but didn't helped me.
Since you're using the Auth, you can utilise the existing Middleware to stop the back button putting them on dashboard.
Wrap the routes you want to protect with a Route::group
Route::group(['middleware' => 'auth'], function () {
Route::get('dashboard', function () {
// Uses Auth Middleware
});
});
Any attempt to access dashboard without login will put them back on the home page (default location in the middleware). Modify the middleware (found in app/Http/Middleware/Authenticate.php) to change the redirect url.
you need to add a middleware in your dashboard so that even if they press back the button they can go back to the page but can't do anything unless they login again.