I’m trying to connect my Backbone app with my server api (using Slim) and I’m using Tuppola / Basic Auth Middleware.
The example is very simple, I’m just trying to get it work. I can achieve this in my server acting directly in the browser. I get the popup window, type the user and password and I get the data.
However when I try to do the same thing using my Backbone app I get all the time the same 401 Unauthorized error.
This is my php code. As I said, works fine when using the browser directly.
My class Container
$container["auth"] = function ()
{
return new \Slim\Middleware\HttpBasicAuthentication([
"path" => "/app_rutas",
"realm" => "Protected",
"users" => [
"test" => "123",
],
"environment" => "REDIRECT_HTTP_AUTHORIZATION"
]);
};
My class Routes
class Routes
{
public static function callbacks($app)
{
$app->add( \Controller::class . ':middleware');
$app->add('auth');
$app->get('/app_rutas/clients', \ClientController::class . ':selectAllClients');
$app->get('/app_rutas/client/{type}/{values}', \ClientController::class . ':selectClient');
$app->put('/app_rutas/client', \ClientController::class . ':newClient');
}
}
And this is my js code where I suppose the problem is that I'm not being able to pass correctly the params to the middleware. I've tried many ways a none works. I thought this should be the one it isn't.
fetchData() {
if (!_.isEmpty(this.clients_id)) {
this.url = this.apiUrl('client', this.clients_id);
this.fetch({ headers: {'Authorization':'Basic test:123'} });
}
},
Thanks for all comments in advance.
This was the correct way to pass the username:password using Backbone:
this.fetch({ headers: {'Authorization':'Basic ' + btoa('test:123')} })
Needed a base64 encode function. Now it finally works.
Related
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.
I am trying to post form data from angular to node.js. The angular post request sends an empty body.
this is my post router
submit function is ts file
onSubmit( loginData ) {
if(!loginData) { return; }
this.userService.addUser( loginData as User )
.subscribe(user => {
this.users.push(user);
});
service used to post data
addUser(user: User): Observable<User> {
// console.log('this is '+user.email);
const url = `${this.usersUrl}/register`;
return this.http.post<User>(url, user).pipe(
tap((newUser: User) => this.log(`added user w/ email=${newUser.email}`)),
catchError(this.handleError<User>('addUser'))
);
}
Please check once by adding the debug whether the loginData is getting passed in the service or not.
If you don't know how to add debug point simply just print the data using console.log(user)
in the method addUser() as the first line.
And if not getting data then simply modify the method call by:
this.userService.addUser(loginData).subscribe(user => {
this.users.push(user);
});
I figured out the problem.
There is no problem in this angular code.
I also checked the network tab as suggested by David, and saw that the payload was being sent.
the problem was this line of code in my node.js server
app.use(express.static('public'))
Instead I had to use
app.use(exrpess.json())
I had copied the template from another application and somehow missed this. Anyway thanks for all your help!
I have a form in ReactJS and every time i click the submit button, the data should pass to adonis api.
ReactJs file
async handleSubmit(e) {
e.preventDefault();
console.log(JSON.stringify(this.state));
await axios({
method: 'post',
url: 'http://127.0.0.1:3333/add',
data: JSON.stringify(this.state),
})
.then(function (response) {
console.log('response',response);
})
.catch(function (error) {
console.log('error',error);
});
}
"http://127.0.0.1:3333/add" is Adonis server with a route '/add'
i don't know how to write in Adonis to post state on that route
Can anybody explain me, please?
in controller's function in get value like this
const data = request.only(['data']) then you get data.
other method to get data like this
const alldata = request.all()
this console this result and view how many result you get
and get data from this alldata.data
First, create a simple controller to handle your data which would receive from your handleSubmit() method in ReactJS app.
Use the below command to create a simple controller:
adonis make:controller TestController --type http
Once created, open the TestController file and make an index method and add the followings which are inside the index method.
'use strict'
class TestController{
// define your index method here
index ({ request }) {
const body = request.post() // get all the post data;
console.log(body) //console it to see the passed data
}
}
module.exports = TestController
After that, register your /add route in start/routes.js file.
Route.post('/add', 'TestController.index') // controller name and the method
And finally, hit the Submit button in your ReactJS app, and test it.
Most likely you be getting CORS issues when you send the request
from your ReactJS app to Adonis server, If so you have to proxy the api request to Adonis server.
To do that, open up your package.json file in ReactJS App, and add the below proxy field.
"proxy": "http://127.0.0.1:3333",
I followed this - http://docs.identityserver.io/en/release/quickstarts/7_javascript_client.html.
Using the following configuration, I tried to login Identity Server from my ReactJS app. http://localhost:3000/callback.html is loaded after successful login. I got id_token and access_token in the url. But, I am sure this callback.html is not the 'src\callback.html' which I have in the folder structure. Even if I delete the 'src\callback.html' file, http://localhost:3000/callback.html#id_token=....... is still loaded. May I know how to change the redirect_uri to a view in my React app (for example Home.js rather than an html file)? I hope I should use route for this. Please advise.
var config = {
authority: "http://localhost:5000",
client_id: "reactSpa",
redirect_uri: "http://localhost:3000/callback.html", // I want it to be something like 'http://localhost:3000/components/home' (a view not an html)
response_type: "id_token token",
scope: "openid profile api1",
post_logout_redirect_uri: "http://localhost:3000/index.html", // same here
};
PS:
I need to set the redirect_uri and post_logout_redirect_uri to any of the views in my React app (not html files) so that I can do the following operation in my Callback view.
new Oidc.UserManager().signinRedirectCallback().then(function () {
window.location = "index.html"; // should be just 'index'
}).catch(function (e) {
console.error(e);
});
First, you need to change client's RedirectUris on identityserver side. I don't know which storage you use but if you use in memory clients here is a sample from official docs:
var jsClient = new Client
{
ClientId = "js",
ClientName = "JavaScript Client",
ClientUri = "http://identityserver.io",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { "http://localhost:7017/index.html" },
PostLogoutRedirectUris = { "http://localhost:7017/index.html" },
AllowedCorsOrigins = { "http://localhost:7017" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"api1", "api2.read_only"
}
};
And also you need to change redirect_uri appropriately on client side config(it must be same as identityserver).
The following comment is the answer:
//Did you try to change redirect_uri on identityserver config to http://localhost:7017/callback and create a Callback component with route configuration(like )? – adem caglin//
It worked after I added Route.
I'm trying to create a test for an API endpoint written with meteor. I'm using jasmine and velocity. It's intended to run within the same project, that's why I'm using them.
The problem comes when I'm trying to run the test and check for data in the endpoint. I have a bootstraped dataset in the mongodb replica, and when I POST it, it doesn't match the one that's bootstrapped in the local app.
Here's the example code:
Jasmine.onTest(function () {
describe('RestApi.MyMethod', function () {
it('Expects to fail because it lacks of valid parameters', function () { /*but it fails because of the user can't be found in the real app*/
var response = "";
var userId = Meteor.users.findOne({"username": "MyUser"})._id;
try {
response = Meteor.http.call(
"POST",
"http://localhost:3000/api/myMethod",
{
data: {
"userId":
},
timeout: 1000
}
);
} catch(error){
expect(error.message.indexOf("failed [400]")).toBeGreaterThan(-1);
expect(error.message.indexOf("Invalid parameters provided")).toBeGreaterThan(-1);
}
expect(response).toBe('');
});
});
});
I think it should point to the mirror's rest api. Is there a way to do that? I changed localhost:3000 to localhost:5000 and it didn't work. How can I check the mirror's port?
Thanks in advance!
Use Meteor.absoluteUrl rather than hard coding the port.
In your code, do this:
response = Meteor.http.call(
"POST",
Meteor.absoluteUrl("api/myMethod"), // this bit has changed.
{
data: {
"userId":
},
timeout: 1000
}
);
When the test runs, your test mirror will dynamically generate an absolute url.