Laravel and Passport, random 401 errors - php

I'm writing a single page web application.
I'm using Vue.js in the frontend and Laravel in the backend.
I included Passport token authentication and I'm getting the auth token sending
var login_data = {
client_id : 2,
client_secret : "SECRET_KEY",
grant_type : "password",
username : "mail",
password : "pass"
}
To this Passport endpoint http://IPADDRESS/oauth/token. Then I authenticate my AJAX requests including this header
{ 'Authorization': 'Bearer ' + ACC_TOKEN }
Most of the time everything works fine but sometimes I get 401 unauthorized. Usually, if I simply do it again the request goes through.
I removed the VerifyCsrfToken middleware from Kernel.php and also added the API route to the exceptions so I don't think that's the problem.
The frequency the error appears seems to change from network to network, meaning when connected to certain networks it almost never happens while sometimes it's constant.
I honestly have no idea why this happens.

My problem was in PROJECTDIR/vendor/lcobucci/jwt/src/Signer/Rsa.php.
Here an openssl function (openssl_get_publickey) sometimes returns something wrong despite the certificate being valid.
I did not manage to find a real solution.
My hack for now is simply changing the code to always return 1.
This does not change the way the token auth works but removes the Rsa check and the 401 errors caused by such malfunction.

Related

How to implement authentication on a REST architecture with Parse

I am currently redoing a legacy web application that uses the PHP Parse SDK, and I am in the login authentication part. In the old application, we used $ _SESSION and ParseToken when doing ParseUser::signIn() and ParseUser::currentUser() to check if you have a session with a valid token, however the new application is being made using the REST architecture, where one of the REST concepts is that the server must not keep state, that is, be stateless, and in that case it would be the client that would have to send the necessary data.
When searching the internet and forums, I saw that it is common for developers to authenticate with JWT, where the client would make a request for a server's route and the server would return a token, and through that token authentication would take place.
I even implemented something using Firebase / jwt-php, where the client [Postman] makes a request for the route /login sending via body [username, password] and in case of success, returns the token to be used in secure route requests.
NOTE: Code is as simple as possible, without validation and cleaning just to show the example.
Action /login
$username = $request->getParsedBody()['username'];
$password = $request->getParsedBody()['password'];
$userAuthenticated = ParseUser::logIn($username, $password);
$payload = [
'data' => $userAuthenticated,
'exp' => time() + 3600
];
$token = JWT::encode($payload, $_ENV['JWT_SECRET_KEY']);
echo json_encode(['token' => $token]);
And the protected routes have a middleware that checks if the time has expired, and if this has happened, an exception with a 401 code is launched.
So far so good, authentication works, the problem I don't know if it's right to do it this way, since I need to give a ParseUser::logIn(), just to generate a session in the database and I don't even use it this session to do some authentication, with the exception of operations in the bank, because from what I saw in the documentation, if there is no valid session in the database, the application will return invalid session token error and also when making the request for another route ParseUser::currentUser() returns null, and this may be a problem in the future.
Does anyone have any idea how I can implement authentication for a REST application made in PHP? I appreciate the help !!
I believe the easiest way would be just replacing the default session storage (which uses $_SESSION) to something else that stores the session in, for example, Redis. Reference: https://docs.parseplatform.org/php/guide/#session-storage-interface
But the way you are doing should also work. You will only have to make sure that, every time that a request comes, you will decode the JWT, get the Parse Session token from there, and use ParseUser::become to set the current user: https://docs.parseplatform.org/php/guide/#setting-the-current-user

Yii2 OpenId Connect error - yii2-authclient returns 400 error "Token not provided" when I try to getUserAttributes()

I'm implementing OpenId Connect into my Yii2 app using the yii2-authclient library. I can login and exchange the code for a token with no problems. I've followed most of the code examples on the web and set a successCallback function that gets called once a user successfully logs in. It looks like this:
public function successCallback(ClientInterface $client)
{
$attributes = $client->getUserAttributes();
}
This code gets called, but calling getUserAttributes() results in the following error:
Exception – yii\authclient\InvalidResponseException
Request failed with code: 400, message:
{"error":"invalid_request","error_description":"Token not provided"}
The logs on the id server show a blank client and user, with an error of invalid_token.
I took a close look at the request I make and I see an access_token element. Any ideas what the problem might be? I can provide more information if necessary.
I figured it out. The problem was that the yii2-authclient library was sending the token as a GET parameter and the ID server was expecting it as a POST param. I upgraded the yii2-authclient library and that solved the problem since a recent change sends the parameter as POST instead of GET.

Access Youtube channels from oauth'd user

I'm trying to get all channels and eventually all videos for the user logged into my site with Google. I'm using Laravel Socialite to set the scope that I think should give the proper permissions. I'm then setting the access token to the session.
public function loginGoogle()
{
return Socialite::driver('google')->setScopes(['https://www.googleapis.com/auth/youtube.readonly',])->redirect();
}
When handling the call back after authenticating the user and saving the access token I run the following:
dd(\Youtube::getService()->channels->listChannels('snippet', ['managedByMe' => true, 'onBehalfOfContentOwner' => session('access_token')]));
\Youtube is just the facade I made to handle Youtube functionality in my site.
When running the code the following error is thrown:
Client error: `GET https://www.googleapis.com/plus/v1/people/me?prettyPrint=false` resulted in a `403 Forbidden` response:
{"error":{"errors":[{"domain":"global","reason":"insufficientPermissions","message":"Insufficient Permission"}],"code":4 (truncated...)
I can't tell if I'm using the incorrect scope or just messing something bigger up. Youtube's documentation hasn't been very helpful in this. They just say the user has to be authorized which...they are?
Been a couple days on this and am not sure where to go next.
Changing
return Socialite::driver('google')->setScopes(['https://www.googleapis.com/auth/youtube.readonly',])->redirect();
to
return Socialite::driver('google')->scopes(['https://www.googleapis.com/auth/youtube.readonly',])->redirect();
seemed to fix it. Looking at the documentation it makes sense why that wouldn't work.

Overcome HTTP basic auth when calling WooCommerce API

I‘m trying to call the WooCommerce/Wordpress API, but the online shop that I‘m trying to reach has HTTP Basic Autj turned on. That means, I need to authenticate once to overcome the HTTP authentication and then I need to authenticate a second time using the api key in order to use the api. Is there a possibility to make an api call whilst overcoming two levels of authentication?
The problem is that if I try to authenticate, I use the following code:
$headers = array('Accept' => 'application/json');
$options = array('auth' => array($username, $password));
$request = Requests::get("$url/$api/$model", $headers, $options);
then I get a 401 (unathorised) response from the api, because I didn't send the api token in my request. But if I use the api token and secret instead of the username and password, I don't even get near the api because I don't overcome the http basic authentication.
Thanks for yout help!
From the looks of it, you're having an issue calling your website due to HTTP Basic Auth.
When it comes to authentication on https://your.site, you can connect to https://your.site and enter foo as the user and bar as the password, OR you can connect to https://foo:bar#your.site.
Hope I helped!
I can't comment on your question for clarification as I don't have the rep. So here goes with an answer!
I think the answer is that you will not overcome two levels of authentication in one call. You will likely contact the server first for an access token using your username and password.
Basic authorization usually means that in the initial http request you set the headers to include 'Authorization': 'Basic _______________________' and then in place of the underscores put a long alphanumeric string that is generated by base64-encoding your username and password (that you would log into WooCommerce with I presume) like so: username:password, and including that colon in between.
If I actually base64 encode username:password it comes out to dXNlcm5hbWU6cGFzc3dvcmQK
so when setting your initial http request headers, include:
'Authorization' : 'Basic dXNlcm5hbWU6cGFzc3dvcmQK'
Except base64 encode you're own username and password (separated by the colon!).
Assuming this works, the api may return an access token to you in a few ways. But if you follow the docs you should be able to figure it out from this point.
Again, really not clear on what you're question is exactly but can't comment so I took a shot. Good luck

Why am I getting error when I use Postman and oauth2 for login access case in apiagility?

I am new to Zend Framework 2. I am trying to get the login access scenario working with Postman (chrome extension). I have gone through the forum but I'm not sure if I'm missing something or not. So here are the steps that I have taken so far:
In MYSQL I have set up the tables accordingly and there is a user with the following fields in the oauth_clients table:
client_id : testclient
client_secret : testpass
redirect_uri : /oauth/receivecode (I'm not sure about the value of
this one could someone please shed some light on this?)
grant_type : password ( I want to use the service for authentication
and authorization to access a website or login access scenario)
The rest of the fields are NULL. No other entries in other tables.
I set the parameters in Postman like this:
Authorization : Oauth2
Headers:
Accept : application/json
Content-Type : application/json
The raw body is like:
{
"client_id":"testclient",
"client_secret":"testpass",
"grant_type":"password"
}
I post the request to:
www.dummy.dev/oauth/authorize
When I post the request this is what I get:
{
"type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html",
"title": "invalid_request",
"status": 302,
"detail": "Invalid or missing response type"
}
Why do I get this error message?
This error is triggered here in the OAuth2 AuthorizeController.
The controller checks whether the $response_type is valid. If not it returns this error message.
On line 313 you see:
protected function getValidResponseTypes()
{
return array(
self::RESPONSE_TYPE_ACCESS_TOKEN,
self::RESPONSE_TYPE_AUTHORIZATION_CODE,
);
}
Those constants are defined in the AuthorizeControllerInterface:
const RESPONSE_TYPE_AUTHORIZATION_CODE = 'code';
const RESPONSE_TYPE_ACCESS_TOKEN = 'token';
So somewhere during the handling of your request this $response_type value is not set correctly. It should either be set as token or code for the request to validate correctly. Not sure where in your config you did something wrong but with this information you should be able to find the problem.
redirect uri is not necessary and could be left null in the database as well. The correct uri to POST is www.dummy.dev/oauth and the raw parameters in Postman are:
{
"client_id":"dev.dummy",
"username":"testclient",
"password":"testpass",
"grant_type":"password"
}
The value of password is stored and encoded (with bcrypt) in the database. client_id and client_secret are not important in this scenario as my own website is the client of my API.

Categories