Moving Passport Google strategy authenticate method from route to controller breaks - javascript

I am using the 'passport-google-oauth' strategy from Passport with Nodejs based Express app to provide authentication. This worked great when I had the logic inside the route file as follows:
router.route('/auth/google')
.get(passport.authenticate('google', {
scope: ['https://www.googleapis.com/auth/userinfo.profile']
});
);
When I moved everything into a controller to make the app more manageable, it stopped working. Specifically, no error is being thrown. The GET request succeeds and the debug method outputs the string, but then it just loads forever and I'm not being redirected to the Google page to select which account to log in with. Any ideas what is going on here and what I need to change to make it flow like fine wine?
// route file
router.route('/auth/google')
.get(backendController.googleAuthenticate);
// controller file
exports.googleAuthenticate = () => {
debug('attempting Google authentication');
passport.authenticate('google', {
scope: ['https://www.googleapis.com/auth/userinfo.profile'],
failWithError: true
});
}

Related

Laravel + Angular - Get 401 unauthenticated on 1 GET method

I'm developing a Laravel + Angular app and i'm getting 401 Unauthorized in only 1 GET request.
Here I explain how I developed my authentication and how it work on Backend and Frontend. I wish you can help me.
I use Laravel Sanctum for manage authentication in my app. Here is how I program the backend.
I get users from my BD table:
Note: I have created a separate controller, to separate the authentication functions from the user functions, even so, I have tried to put this function in my AuthController and it has not given me any result.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
class UsersController extends Controller
{
public function getAllUsers()
{
return User::all();
}
}
As I want you to only be able to retrieve all the DB users if you are authenticated, in my api.php file I put the path inside the middleware:
Route::middleware('auth:sanctum')->group(function()
{
Route::post('logout', [\App\Http\Controllers\AuthController::class, 'logout']);
Route::get('getAuthUser', [\App\Http\Controllers\AuthController::class, 'getAuthUser']);
//Admin actions
Route::post('createUser', [\App\Http\Controllers\AuthController::class, 'createUser']);
Route::get('getAllUsers', [\App\Http\Controllers\UsersController::class, 'getAllUsers']);
});
If I make the request from the Postman everything works correctly, if I am not authenticated it gives me an error and if I have previously authenticated it returns all the DB users just as I expected. By the way, I am using cookies to send the jwt to the Frontend.
The problem is when in my Angular app I request my backend with the GET method to retrieve these users and display them in a table. In addition, the code to retrieve the users is within a condition in which it is looking at whether the user is authenticated or not. The truth is that I do not understand what may be happening.
getUsers(): void
{
//Check if user is authenticated
this.http.get('http://localhost:8000/api/getAuthUser', { withCredentials: true }). subscribe(
(res: any) =>
{
Emitters.authEmitter.emit(true);
Emitters.roleEmitter.emit(res.role);
//Get all users
this.http.get('http://127.0.0.1:8000/api/getAllUsers', { withCredentials: true }). subscribe(
res =>
{
this.users = res;
}
)
},
err =>
{
Emitters.authEmitter.emit(false);
Emitters.roleEmitter.emit("none");
alert("You should be authenticated for this.");
}
);
}
The first request that you see above getAuthUser, makes the request to the Backend in the same way as the second request getAllUsers and the first one works perfectly and the second one does not, it is in which I get an err. I call the getUsers() method in the ngInit().
I hope I have explained myself well. Any information you need to know let me know. Thank you.
The solution was in the request that gave the error to change the path of the api, instead of putting 127.0.0.1 putting localhost.

Keycloak js not executing THEN after init

I am trying to integrate Keycloak login into my React app and I'm trying to get the JWT from keycloak. Here is the code:
const [keycloakState, setKeycloakState] = useState<any>();
const login = () => {
const keycloak = Keycloak("/keycloak.json");
keycloak.init({onLoad: 'login-required'}).then(authenticated => {
console.log('kk', keycloak)
console.log('at', authenticated)
setKeycloakState({ keycloak: keycloak, authenticated: authenticated });
}).catch(err => {
alert(err);
});
console.log('log after')
}
The login function is triggered when a button is clicked. It redirects properly to keycloak, I can log in and I am properly redirected to the app. The problem is that after the redirect back to the app with proper login the code in the then part of the chain is not executed, and even the 'log after' does not appear in the logs. The catch error part works fine.
Why might this be happening? I have keycloak-js added to my project.
I used to face this problem before. The way that I passed is separating the "init" function and then invoke it later.
Here is my example on jsFiddle: 'https://jsfiddle.net/gzq6j3yu/1/'
Our solution was to use the functions onAuthSuccess and onAuthError avaliable on the KeycloakInstance keycloak-js provides. (The documentation around this is a little shaky but you can find them if you check out the source code.) As the names imply these functions get called when an auth attempt is successful or unsuccessful, respectively.
note: in the following snippets this._instance replaces OP's keycloak constant.
Basic code snippet:
import Keycloak from 'keycloak-js';
...
// pulled from a class's init function from a custom Keycloak helper class so won't translate one for one but you get the point.
this._instance = Keycloak(configObject);
this._instance.onAuthSuccess = () => {
// code to execute on auth success
};
this._instance.onAuthError = () => {
// code to execute on auth error
};
this._instance.init(initOptions)
...
We also had a getter to get the token on the KeycloakInstance (or empty string) on the same class. This is an easy way to refer to the token in your code to check if it actually exists, etc. Here's what that'd look like inside the class.
get token() {
return this._instance ? this._instance.token : '';
}
Hope this can help out some folks.
I think the reason your fulfilled callback is not executed is the way your app interacts with Keycloak. You initialize the Keycloak-Adapter with onLoad: 'login-required' which will redirect the user to Keycloak - which means the Javascript execution is interrupted at this point. Keycloak will redirect the user back to your app and since you wrapped the Keycloak-Adapter in a function which is only executed when a button is clicked, the promise callback is not executed.
Simple example:
// do this on page load
keycloak.init({onLoad: 'login-required'}).then((authenticated) => {
console.log('authenticated', authenticated)
})
You will not see a "authenticated", false in your console when you open up your app. If the user is not authenticated, he will be redirected (so no chance to execute that callback). If he then comes back and is authenticated, the callback will be executed and authenticated should be true.
If you want the user to click a button, a setup like this should work:
// do this somewhere early in your App or main.js and in a way that this code is executed on page load
const keycloak = new Keycloak(configuration);
keycloak.init({onLoad: 'check-sso'}).then((authenticated) => {
if (authenticated) {
// do what needs to be done if sign in was successful, for example store an access token
} else {
// handle failed authentication
}
}).catch(err => {
alert(err);
});
const login = () => { // this could be an on-click event handler
keycloak.login();
};
check-sso won't redirect the user to Keycloak if unauthenticated, so the user can trigger the login when needed.
Keep in mind that your JavaScript code will run twice and you have to cover both cases, first the user is not authenticated and needs to be redirected to Keycloak and a second time once the user comes back from Keycloak (then we should get the information that the user is authenticated in .then().

Loopback Angular SDK Login Issue

I created a "user" named model with base class "User". I'm trying to login a user in Angular App using lb-ng generated service but it's not logging in.
In my Login controller I invoked User.login() providing email and password but its giving some weird error.
Even I included this code in my app.js
// Use a custom auth header instead of the default 'Authorization'
LoopBackResourceProvider.setAuthHeader('X-Access-Token');
// Change the URL where to access the LoopBack REST API server
LoopBackResourceProvider.setUrlBase('http://.../api');
In loginController
console.log(User.login({ email: "shah.khokhar#hotmail.com", password: "12345" }));
But it's giving this validation error:
Kindly help me on this.
Thanks,
If you could post your user.json file and your actual angular code then it would be more clear. But as far as I can see, there are things you are doing wrong.
You are making a request to User model instead of your custom user model which obviously won't work as your user data is present in your custom model and not the built in User model
You are most probably making a POST request to a wrong method than login method as login method request url looks something like this
http://localhost:3000/api/users/login
Here's a working sample code for login function which I use for my project
self.login = function () {
var data = {
email: self.email,
password: self.password
};
users.login(data).$promise
.then(function (user) {
$state.go('home');
})
.catch(function (err) {
$state.go('auth.register');
});
};
Hope this helps.

Rewrite URL in AngularJS Factory

The app I'm developing allows users to change the IP of the server (where the REST API is). This address is stored in a variable that can change, but the problem is that when the services are instantiated, the base URL cannot be changed. Following this answer I was able to change the url of some of the services, but I can't do the same for those who have POST actions.
I've tried several configurations, but there's always a problem. For example, this:
// Services file
app.factory('Bookings', BookingsFactory)
function BookingsFactory($resource, GlobalVariables) {
return $resource('http://:url/api/bookings/:id/', null, {url: '#url'});
}
//Controllers file
Bookings.save(booking, {url: GlobalVariables.IPServer});
Throws this error message "net::ERR_NAME_NOT_RESOLVED", because the request URL is not correct: "http://api/bookings/?end_time=2015-06-30T09:30&name=Reunion&room=1&start_time=2015-06-30T09:43&started=true".
If I call it like this:
//Services file
app.factory('Bookings', BookingsFactory)
function BookingsFactory($resource, GlobalVariables) {
return $resource('http://:url/api/bookings/:id/', {url: '#url'});
}
//Controllers file
Bookings.save({booking: booking, url: GlobalVariables.IPServer});
I get a 400 BAD REQUEST error, and the response asks for content for all the required fields: "This field is required."
I'm using AngularJS v1.3.13. Is there a way to change the base URL in every petition with this approach, even on POST requests? Or even better, is there a way to update the URL in every factory of the application after the app is started?
In an app that I work on I use the $rootScope to hold my base server URL for all requests. I don't know if that's a good way to use $rootScope or not, but what's for sure is that the app is working.
oops sorry I forgot to also add that I can change the base URL while the app is running, which is what you need.

Node JS Route Behavior makes no sense

I'm trying to make a simple authentication page using Node with Express framework.
At this moment, I'm not particularly worried about the weak protection.
However, my route file is displaying weird behavior.
Here is the code:
var express = require('express');
var router = express.Router();
var admin = require("../controllers/admin");
router.get('/', function(req, res) {
console.log('Entered top route.');
if(req.body.isAuthenticated) {
res.redirect('admin/index');
} else {
res.redirect('admin/login');
}
});
router.post('/authenticate', function(req,res) {
if(req.body.pword == "key") {
console.log("Resetting body.isAuth'ed");
req.body.isAuthenticated = true;
console.log("New val: " + req.body.isAuthenticated);
res.redirect('admin/index');
} else {
console.log("Failed login attempt: " + req.body.pword);
res.redirect('admin/login');
}
});
router.get('/login', admin.login);
router.get('/index', admin.index);
module.exports = router;
The idea is that the route is entered, upon which we hit the top route (properly logged by console). This redirects based on whether a req variable is set. This all works properly, and the login (I'm using jade templating) is properly rendered. The login file has a form which calls back to this routing file with 'admin/authenticate'. This also works properly; I'm able to properly retrieve the input (confirmed via console logs). However, the actions I take in the /authenticate/ function, even though they are the exact same thing I do in the '/' route right above, fail. I get 404's and Express Not Found printouts which are entirely useless.
My console properly logs 'Failed login attempt' or 'Resetting body...New val: true", but then doing the exact same res.redirect that is initially done in the router.get('/') method above fails, whereas the res.redirects in that function properly redirect and render the correct values.
Any ideas what could be wrong? I could post the admin.login/admin.index methods in the controllers/admin file. However, they're very simple and I think this error stems from a basic misunderstanding of the difference between get and post methods or something (this is my first time using Node).
Thanks!
I think the issue is because of the relative path.
Doing res.redirect('admin/index') from path / and path /authenticate is not same.
res.redirect('admin/index') from /authenticate will redirect user to /authenticate/admin/index, may be thats why it is giving 404.
Try to change res.rediret('admin/index') to res.redirect('/admin/index') in authenticate callback.

Categories

Resources