Description
I'm getting an error when attempting to create a stripe subscription using Laravel + the API.
Before you create the subscription you must get the token by requesting it, I have successfully created this token and I'm now using the "createSubscription()" method from the API (referenced in my code), but this is where the error is occurring.
Code
public function create()
{
$user = Auth::user();
$plan = 'prod_**********';
// Do some checks
if ($user->subscribed('main')){
return [
'status' => 'failed',
'message' => 'You are already subscribed!',
];
}
// Set the stripe Key
Stripe::setApiKey(env('STRIPE_SECRET'));
// Create the stripe token
try {
$stripeToken = Token::create([
'card' => [
'number' => str_replace(' ', '', Input::get('number')),
'exp_month' => Input::get('exp_month'),
'exp_year' => Input::get('exp_year'),
'cvc' => Input::get('cvc')
]
]);
}
catch (\Stripe\Error\InvalidRequest $e)
{
return [
'status' => 'failed',
'message' => $e->getMessage(),
];
}
try{
// This is the line thats failing
$user->newSubscription('main', $plan)->create($stripeToken);
} catch (\Stripe\Error\InvalidRequest $e) {
dd($e->getMessage());
}
return [
'status' => 'success',
'message' => 'Subscription was successful!',
];
}
The Error
The error in full is:
Invalid request. Hint: check the encoding for your request parameters
and URL (http://en.wikipedia.org/wiki/percent-encoding). For
assistance, email support#stripe.com.
I've spoken to stripe support and they're saying they think the error is on my end, everything seems good on the stripe end.
I've checked the card detailed and customer details are correct (This is why the token being created).
I've searched this error but nothing seems to come up for this, there are other questions somewhat similar but no answers.
I've uninstalled / reinstalled laravel-cashier package to no success.
Whats strange is how i've managed to solve this problem. It would seem that passing the entire stripe token does not work and instead I only needed to pass the token ID.
Simply changing
$user->newSubscription('main', $plan)->create($stripeToken);
to this
$user->newSubscription('main', $plan)->create($stripeToken->id);
Solved this error
Invalid request. Hint: check the encoding for your request parameters
and URL (http://en.wikipedia.org/wiki/percent-encoding). For
assistance, email support#stripe.com.
I'm sure that nowhere in either documentation is states that this is the solution? Or maybe I overlooked this somewhere... but this has solved it for me.
how can i authenticate user and create jwt token for that with username field in users table and password fields in another table ?
$credentials = [
'phone' => $request->phone,
'confirm.password' => $request->confirmation_code,
];
try {
// attempt to verify the credentials and create a token for the user
if (! $token = JWTAuth::attempt($credentials)) {
return response()->json(['state' => False, 'error' => 'Invalid Credentials.'], 401);
}
} catch (JWTException $e) {
// something went wrong whilst attempting to encode the token
return response()->json(['state' => False, 'error' => 'can not create token !'], 500);
}
my password is in confirm table and password field. the user table in related to confirm table in thier model.
How to force the user to fill the form after login with google or facebook. I ma using laravel 5.4 with socials. In my app i want to allow google and facebook login but user can create a standard user too. When login with one of the social providers (facebook or google) i want the user to fill other fields in the form to complete the registration.
The handleProviderCallback:
public function handleProviderCallback($provider)
{
try{
$socialUser = Socialite::driver($provider)->stateless()->user();
}catch (Exception $e){
return redirect('/');
}
// check if we have logged PROVIDER
$socialProvider = Social::where('provider_id', $socialUser->getId())->first();
// if we don`t have a provider create a user and provider
if(!$socialProvider){
// i want the user to go back in the form and finish the registration
return view('auth.socials')->with('socialUser', $socialUser)->with('provider', $provider);
}
else{
// return the user
$user = $socialProvider->user;
}
// log the user in our app :)
auth()->login($user);
return redirect('/home');
the problem is when submiting the form i get an exception:
Client error: `POST https://accounts.google.com/o/oauth2/token` resulted in
a `400 Bad Request` response:
{
"error" : "invalid_grant",
"error_description" : "Invalid code."
}
If i use the method handleProviderCallback like this:
public function handleProviderCallback($provider)
{
try{
$socialUser = Socialite::driver($provider)->stateless()->user();
}catch (Exception $e){
return redirect('/');
}
// check if we have logged PROVIDER
$socialProvider = Social::where('provider_id', $socialUser->getId())->first();
// if we don`t have a provider create a user and provider
if(!$socialProvider){
$user = User::firstOrCreate(
['email' => $socialUser->getEmail()],
// i have to manualy add the missing fields
['name' => $socialUser->getName(), 'forename' => 'test', 'password' => '' ,'address' => 'adasda', 'country' => 'asasfasf', 'town' => 'asfasfsfsfs', 'legal_person' => '0', 'newsletter' => '1', 'phone' => '1235241521']
);
// add provider for this user
$user->socials()->create(
['provider_id' => $socialUser->getId(), 'provider' => $provider]
);
}
else{
// return the user
$user = $socialProvider->user;
}
// log the user in our app :)
auth()->login($user);
return redirect('/home');
}
the user get logged in, but as you can see i have to manually insert the missing fields in the firstOrCreate method (which are required in the users table)
Any suggestion how to do this?
So, I'm using Laravel+Passport and so far is working fine.
But, I would like to made a small change to the passport code(well, not in the vendor folder, I hope), once that I would request the User to change it's password in case that he is doing the first login.
So, what I would need is two things (I believe):
1 - How can I add one more info to the oauth/token response? Together with the access_token, I would like to add one column from the DB that is needsNewPassword=true/false.
2 - In case that needsNewPassword is true, then, the app will redirect to another screen, where the user will set a new password. I would set the new password, remove the flag for needsNewPassword and send back a new access_token to the user. The user then, would use only that access_token. How can I regenerate a new access_token?
Thanks for you help! João
Right,
I answering my own question, in case someone needs to do the same. Maybe is not the best way, but is working.What I did is:
Create a new route, like /api/login that points to a method (be sure that is Outside of your middleware "auth", once that it's not sending the token in thi call). E.g: Route::post('/login', 'Auth\LoginController#apiLogin');
in the method, you do a request to the oauth/token and, with the result, you add the fields that you want.
test
function apiLogin(Request $request) {
$tokenRequest = $request->create('/oauth/token', 'POST', $request->all());
$request->request->add([
"client_id" => 'your_client_id',
"client_secret" => 'your_client_secret',
"grant_type" => 'password',
"code" => '*',
]);
$response = Route::dispatch($tokenRequest);
$json = (array) json_decode($response->getContent());
$json['new_value'] = '123456';
$response->setContent(json_encode($json));
return $response
}
This is working for me. In my case, I also have just one app so, my client_id, client_secret, grant_type and code is added in the server side. The client only need to pass username(or email, depends of what you are using) and password and then it will get the access_token and the other info that I want to send as well.
Hope that this helps someone else too.
Cheers,
joao
#joao.sauer
Your own answer is working like a charm, but if you wan't a bit more freedom, you could extend Passport's own AccessTokenController.
A simple example:
use App\Models\User;
use Exception;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use League\OAuth2\Server\Exception\OAuthServerException;
use Psr\Http\Message\ServerRequestInterface;
use Response;
class AccessTokenController extends \Laravel\Passport\Http\Controllers\AccessTokenController
{
public function issueToken(ServerRequestInterface $request)
{
try {
//get username (default is :email)
$username = $request->getParsedBody()['username'];
//get user
$user = User::where('email', '=', $username)->firstOrFail();
//issuetoken
$tokenResponse = parent::issueToken($request);
//convert response to json string
$content = $tokenResponse->getBody()->__toString();
//convert json to array
$data = json_decode($content, true);
if(isset($data["error"]))
throw new OAuthServerException('The user credentials were incorrect.', 6, 'invalid_credentials', 401);
//add access token to user
$user = collect($user);
$user->put('access_token', $data['access_token']);
return Response::json(array($user));
}
catch (ModelNotFoundException $e) { // email notfound
//return error message
}
catch (OAuthServerException $e) { //password not correct..token not granted
//return error message
}
catch (Exception $e) {
////return error message
}
}
}
credits to Messi89:
Laravel Passport - Customize The Token Response
I found a simple solution without need new request, controller or extends, just add parameters to request and call issueToken via app, it can useful for starter:
// in routes/api.php
Route::post('/token',function(Request $request){
$request->request->add([
'grant_type' => 'password',
'client_id' => '2',
'client_secret' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
]);
return app()->call('\Laravel\Passport\Http\Controllers\AccessTokenController#issueToken');
});
Also can add try...catch block to handle exceptions or add parameters to response before send to client
Route::post('/token',function(Request $request){
$request->request->add([
'grant_type' => 'password',
'client_id' => '2',
'client_secret' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
]);
try {
$response = app()->call('\Laravel\Passport\Http\Controllers\AccessTokenController#issueToken');
$newResponse = json_decode($response->content());
// Add parameters to response here
$newResponse->user = ['user'=>'user','pass'=>'pass'];
return Response()->json($newResponse);
}catch (Laravel\Passport\Exceptions\OAuthServerException $e) {
if ($e->statusCode() == 400) {
return response()->json(['message' => 'Invalid request. Please enter username and password.'], $e->statusCode());
} else if ($e->statusCode() == 401) {
return response()->json(['message' => 'Your credentials are incorrect. Please try again.'], $e->statusCode());
}
return response()->json('Something went wrong on the server. Please try later.', $e->statusCode());
}
});
I have an issue with user authentication. I can create a new user and use laravel's Hash::make command to encrypt the password which all appears to be working correctly see database record below :
Now for the login script. I did a dump die on the $input and confirmed it has the post data from the login form inside it.
Code :
public function CheckLogin()
{
$input = Request::all();
// create our user data for the authentication
$userdata = array(
'Email' => $input['email'],
'Password' => $input['password']
);
// attempt to do the login
if (Auth::attempt($userdata)) {
// if(Auth::attempt(['Email' => $input['email'], 'Password' =>$input['password'], 'ArchivedOn' => null])){
//return redirect()->intended('devices');
return redirect()->intended('devices');
} else {
$err = 'Login Failed Please check credentials and try again.';
return view('welcome', compact('err'));
}
}
The Auth::attempt appears to always return false as it always re-directs to the welcome page with the error message I specified.
I expectect I am missing something obvious but I thought I would ask for a fresh pair of eyes on this as I can't see the problem.
Your userdata should be:-
$userdata = array(
'Email' => $input['email'],
'password' => $input['password']
);
Note: You need to write Password 's p character in small letter. You can change email with Email or Username whatever name you want but password must be 'password'.
Check this link for more detail.