Im new at Laravel, i made a login page for my backend application(its working fine) and then i did the JWT documentation to install and begin to use(https://jwt-auth.readthedocs.io/en/develop/).
In my Controllers i used after:
public function __construct()
{
$this->middleware('auth:api', ['except' => ['login']]);
}
Now everytime i try to enter my same login i cant.
How can i enter my login now with JWT?
If you're using Laravel 8, the newly recommended route is to use Laravel's Sanctum feature:
https://laravel.com/docs/8.x/sanctum
For this, if you want stateful logins, you simply post to any controller that then makes an Auth::attempt call like this:
class AuthController extends Controller
{
/**
* Store a newly created resource in storage.
*
* #param Request $request
* #throws ValidationException
*/
public function store(Request $request)
{
$request->validate([
'email' => 'required|email',
'password' => 'required',
]);
$credentials = $request->only('email', 'password');
if (!Auth::attempt($credentials, true)) {
throw ValidationException::withMessages([
'email' => ['The provided credentials are incorrect.'],
]);
}
}
}
I recently set up my login system successfully on React using this package:
https://github.com/koole/react-sanctum
For Stateless, you can follow the documentation here:
https://laravel.com/docs/8.x/sanctum#api-token-authentication
Related
I'm using external identity provider to authenticate users, created a SPA client (got client_id & client_secret), configured API with audience & scope, so once users authenticated they will get access_token (will be authorized) to access multiple custom micro-services (APIs).
When my custom API receives a request with a bearer Access Token (JWT) the first thing to do is to validate the token. In order to validate JWT I need to follow these steps:
Check that the JWT is well formed (Parse the JWT)
Check the signature. My external identity provider only supports RS256 via the JWKS (JSON Web Key Set) URL (https://{domain}/.well-known/jwks.json), so I can get my public key following this URL.
Validate the standard claims
Check the Application permissions (scopes)
There are a lot of packages/libraries (i.e. https://github.com/tymondesigns/jwt-auth) to create JWT tokens but I can't find any to validate it using those steps above. Could anyone please help to find suitable Laravel/PHP package/library or move me to the right direction in order to achieve my goals (especially point #2).
I did something similar in the past, I don't know if this may help but I'll give it a try. To use a public key, you should download it, put it somewhere on the disk (storage/jwt/public.pem for example) and then link it in the jwt config config/jwt.php with the ALGO (you can see supported algorithms here
'keys' => [
// ...
'public' => 'file://'.storage_path('jwt/public.pem'),
// ...
],
'algo' => 'RS256',
Then, you should have a custom Guard, let's call it JWTGuard:
<?php
namespace App\Guard;use App\Models\User;
use Illuminate\Auth\GuardHelpers;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request;
use Tymon\JWTAuth\JWT;class JWTGuard implements Guard
{
use GuardHelpers;
/**
* #var JWT $jwt
*/
protected JWT $jwt;
/**
* #var Request $request
*/
protected Request $request;
/**
* JWTGuard constructor.
* #param JWT $jwt
* #param Request $request
*/
public function __construct(JWT $jwt, Request $request) {
$this->jwt = $jwt;
$this->request = $request;
}
public function user() {
if (! is_null($this->user)) {
return $this->user;
}
if ($this->jwt->setRequest($this->request)->getToken() && $this->jwt->check()) {
$id = $this->jwt->payload()->get('sub');
$this->user = new User();
$this->user->id = $id;
// Set data from custom claims
return $this->user;
}
return null;
}
public function validate(array $credentials = []) { }
}
This should do all your logic of validation, I used a custom user implementation, the class signature was like:
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Model;
class User extends Model implements AuthenticatableContract {
// custom implementation
}
Finally, you should register the guard in the AuthServiceProvider and in the auth config
public function boot()
{
$this->registerPolicies();
$this->app['auth']->extend(
'jwt-auth',
function ($app, $name, array $config) {
$guard = new JWTGuard(
$app['tymon.jwt'],
$app['request']
);
$app->refresh('request', $guard, 'setRequest');
return $guard;
}
);
}
then allow it in the config
<?php
return [
'defaults' => [
'guard' => 'jwt',
'passwords' => 'users',
],
'guards' => [
// ...
'jwt' => [
'driver' => 'jwt-auth',
'provider' => 'users'
],
],
// ...
];
You can then use it as a middleware like this:
Route::middleware('auth:jwt')->get('/user', function() {
return Auth::user();
}
Does this sound good to you?
In the end I've used the Auth0 SDK for Laravel - https://auth0.com/docs/quickstart/backend/laravel/01-authorization. Nice and clean solution.
I'm using laravel breeze as auth scaffolding package I want to know How can I
create two diffirent registration form for two User Types here is a simple explanation of hwat I want to achieve:
resources/auth/developer :
developer-register.blade.php
resources/auth/designer :
designer-register.blade.php
if the Visitor choose to register as "developer" it will display a diffirent form. and same thing for if the Visitor choose to register as "designer" it will display a diffirent form with fields.
I wish you understand what I want to achieve with this easy explanation.
Ok, so i've not used laravel/breeze myself (yet) but it shouldn't be much different from doing it in standard Laravel!
Views
By default, it looks like the breeze scaffolding is going to hit a create() method on the RegisteredUserController which will return a single view like so:
RegisteredUserController.php
/**
* Display the registration view.
*
* #return \Illuminate\View\View
*/
public function create()
{
return view('auth.register');
}
You have a few options here:
Replace this view with another
Add some logic to change the view which is returned based on the request being made (you can inject a Request object into the route like any other)
public function create(Request $request)
{
if ($request->has('developer')) {
return view('auth.developer-register');
} else {
return view('auth.designer-register');
}
}
Keep the original auth.register view and handle the logic in the blade template.
Registration
The forms on each of your registration pages will have an action that points to a controller route. This will likely be the RegisteredUserController within which you will find a store() method that handles the creation of a User model.
RegisteredUserController.php
/**
* Handle an incoming registration request.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\RedirectResponse
*
* #throws \Illuminate\Validation\ValidationException
*/
public function store(Request $request)
{
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|confirmed|min:8',
]);
Auth::login($user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]));
event(new Registered($user));
return redirect(RouteServiceProvider::HOME);
}
As you can see, this store() method is handling the creation of a User model and then authenticating it before redirecting the user to the home route.
What you could do, is check the request for the the requested user type and then use a switch statement to change the type of use being created.
switch ($request->get('user_type'))
case 'developer':
$user = Developer::create([ /* add details here */ ]);
break;
case 'designer':
$user = Designer::create([ /* add details here */ ]);
break;
Auth::login($user);
I hope this will at least inspire you with your own solution!
I am building an API and I am using Laravel Passport for authentication.
The API is being used for our mobile app so we're using the Password Grant Client.
Everything works great, and a user can login to get an access token. We have created a register endpoint which allows a user to sign up. We need the API to return an access token at this point too.
Looking through the docs there is no way to create an access token programmatically.
How can I create an access token for a Password Grant Client in my controller? I obviously don't want to do a HTTP request to my own API to get it.
I know I can use a Personal Access Grant Client and call createToken on the user model, but that means the access token is associated with a different Client. This doesn't seem right to me.
Try something like this
class UserController extends Controller
{
protected function login(Request $request)
{
$request->request->add([
'grant_type' => 'password',
'client_id' => '3',
'client_secret' => '6BHCRpB4tpXnQvC1DmpT7CXCSz7ukdw7IeZofiKn',
'scope' => '*'
]);
// forward the request to the oauth token request endpoint
$tokenRequest = Request::create('/oauth/token','post');
return Route::dispatch($tokenRequest);
}
}
I've been toying with Passport for a couple of weeks now and from what I've seen in the documentation it doesn't expose many of the methods it uses for creating tokens. While you may not easily be able to "create an access token for a Password Grant Client in my controller" - what you can do is use Route::dispatch to forward the request for a token to your Passport Password Grant route.
To do this in the controller you are using to issue tokens, use the AuthenticatesUsers trait so you have access to the Password Grant route, create a request, and dispatch that request to the Password Grant route:
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class IssueTokensController extends Controller
{
use AuthenticatesUsers;
protected function issueApiToken(Request $request)
{
// forward the request to the oauth token request endpoint
$tokenRequest = Request::create(
'/oauth/token',
'post'
);
return Route::dispatch($tokenRequest);
}
}
This method of course requires you to have set up Passport and a Password Grant Client.
This answer is based off of another answer to a similar question by Raymond Lagonda - see https://stackoverflow.com/a/40433000/4991377
Patrick has got the right idea, and this is what I ended up doing:
(I don't think Sanju's answer is right because you need to make a http request)
<?php
namespace MyApp\Http\Controllers\API;
use Illuminate\Http\Request;
use Laravel\Passport\Http\Controllers\ConvertsPsrResponses;
use League\OAuth2\Server\AuthorizationServer;
use MyApp\Http\Controllers\APIController;
use Illuminate\Auth\AuthenticationException;
use Zend\Diactoros\ServerRequest;
use Zend\Diactoros\Response as Psr7Response;
class LoginController extends APIController
{
use ConvertsPsrResponses;
/**
*
* #param Request $request
* #param AuthorizationServer $authServer
* #return \Illuminate\Http\JsonResponse
* #throws AuthenticationException
* #throws \League\OAuth2\Server\Exception\OAuthServerException
*/
public function login(Request $request, AuthorizationServer $authServer)
{
$token = $this->getPasswordToken($request, $authServer);
$data = [
"token_details" => $token,
];
return $this->successResponse(
'Successful Login',
200,
$data
);
}
/**
* #param $request
* #param AuthorizationServer $authServer
* #return mixed
* #throws \League\OAuth2\Server\Exception\OAuthServerException
*/
private function getPasswordToken($request, AuthorizationServer $authServer)
{
$parsedBody = [
'grant_type' => 'password',
'client_id' => config('app.client_id'),
'client_secret' => config('app.client_secret'),
'username' => $request->username,
'password' => $request->password,
'scope' => '',
];
$serverRequest = new ServerRequest(
$request->server(),
[],
null,
$request->method(),
'php://input',
$request->header(),
[],
[],
$parsedBody
);
$response = $this->convertResponse(
$authServer->respondToAccessTokenRequest($serverRequest, new Psr7Response)
);
return json_decode($response->getContent());
}
}
I know I can use a Personal Access Grant Client and call createToken on the user model, but that means the access token is associated with a different Client
not sure what you mean by that, could you explain more?
Now this is not ideal but you might be able to inject \League\OAuth2\Server\Grant\PasswordGrant and use
respondToAccessTokenRequest(ServerRequestInterface $request
ResponseTypeInterface $responseType,
\DateInterval $accessTokenTTL)
you would have to build all those objects, but this is the only public method for password that returns any token information.
Pulling my hair out over what seems a simple task. I use the username instead of email in my AuthController using the following code:
/**
* Set the login system to use username instead of email address
* #var string
*/
protected $username = 'username';
This has worked fine for a long time (when I wasn't planning on users activating their accounts). However, now I need users to activate their accounts, I know I need to do additional checks on login before they can see their dashboard.
I have modified the postLogin() method below, to what I thought would be correct:
public function postLogin(Request $request)
{
$this->validate($request, [
'username' => 'required', 'password' => 'required',
]);
$credentials = $request->only('username', 'password');
$credentials = array_add($credentials, 'confirmed', '1');
if ($this->auth->attempt($credentials, $request->has('remember')))
{
return redirect()->intended($this->redirectPath());
}
return redirect($this->loginPath())
->withInput($request->only('username', 'remember'))
->withErrors([
'username' => $this->getFailedLoginMessage(),
]);
}
But all I get is the following error:
Undefined property: App\Http\Controllers\Auth\AuthController::$auth
What is it that i'm doing wrong?
Andy
Just one glitch that I see there.
if ($this->auth->attempt($credentials, $request->has('remember')))
should be
if (Auth::attempt($credentials, $request->has('remember')))
In Laravel 5.1, the $auth attribute does not exist in the AuthController class constructor, as explained in the 5.1 upgrade guide. So you're referencing a property which does not exist.
I'm working in application which requires a custom login.
I've to follow this flow.
User will enter login page.
User submit login page.
Application will check if the user is in database
3.1 (If user not in database | it will send a request to a third-party and check if login succeeded)
3.2 If user is in database verify password.
Now i've done class for the third-party and the code will work as this
$third = new Libraries\ThirdParty();
$third->login($username, $password);
$third->login will return true if login succeeded.
Now the question is how to link this logic. with the laravel pre-defined function Auth::check()
When you install laravel, it comes with a default login, that uses a trait:
class AuthController extends Controller {
use AuthenticatesAndRegistersUsers;
/**
* Create a new authentication controller instance.
*
* #param \Illuminate\Contracts\Auth\Guard $auth
* #param \Illuminate\Contracts\Auth\Registrar $registrar
* #return void
*/
public function __construct(Guard $auth, Registrar $registrar)
{
$this->auth = $auth;
$this->registrar = $registrar;
$this->middleware('guest', ['except' => 'getLogout']);
}
}
this class use the trait for login stored in: vendor\laravel\framework\src\Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers.php
you can overwrite the methods from this class to put your own logic, for example in the class AuthController you can define a new:
function postLogin(){
//your new logic for login
}
and it gonna respect your function instead the trait funcion.
anyway, the logic behind the postLogin from auth trait is:
public function postLogin(Request $request)
{
$this->validate($request, [
'email' => 'required|email', 'password' => 'required',
]);
$credentials = $request->only('email', 'password');
if ($this->auth->attempt($credentials, $request->has('remember')))
{ //this if validate if the user is on the database line 1
return redirect()->intended($this->redirectPath());
//this redirect if user is the db line 2
}
return redirect($this->loginPath())
->withInput($request->only('email', 'remember'))
->withErrors([
'email' => $this->getFailedLoginMessage(),
]);
//redirect again to login view with some errors line 3
}
you can do two things:
edit the trait itself (bad practice) to put your own logic
define your own postLogin function in AuthController and copy the logic but edit it with your own custom logic.
Edit
to be more conrete with your points:
User will enter login page: you can use the default login page that laravel gives you, or you can overwrite getLogin function and redircet to your own view.
User submit login page: the form action needs to be: {{ url('/auth/login') }} or whatever route you put to postLogin()
Application will check if the user is in database: in the code line 1
3.1 (If user not in database | it will send a request to a third-party and check if login succeeded): in the code line 3
3.2 If user is in database verify password: in the code line 2
custom login 100% wroking without auth
use Hash;
$data->password = Hash::make(($request->password)); Encript Password
public function requestEmployee(Request $request)
{
if ($data = AddEmployee::where('name', $request->name)->first()) {
$pass = Hash::check($request->password, $data->password);
if ($pass) {
echo "sucess";
} else {
echo "Password Not Valid";
}
} else {
echo "Username Not Valid" . "<br>";
}
}