Question Password reset token in Laravel Breeze Inertia React - reactjs

I have a problem to use password reset view which demanding an token to create the view in laravel breeze combine with inertiajs and reactjs.
my question is :
Q1. Where is the token generated? or where do i retrieve the token?
//route
Route::get('reset-password/{token}', [NewPasswordController::class, 'create'])
->name('password.reset');
//controller
public function create(Request $request)
{
return Inertia::render('Auth/ResetPassword', [
'email' => $request->email,
'token' => $request->route('token'),
]);
}
as you can see this route demanding a token to create the view but i dont know how to generate the token. and i cant see any page access this route so there is no example about this.
Q2. How do i pass the token to controller
<Link method="get" href={route('password.reset')} data={{ token: token }} as="button">
Reset
</Link>
im planing to do like code above which i can click from user data grid based on user id so only admin can reset your password. or any better idea to implement this?.
thankyou in advance

If you installed breeze/laravel fresh installation you can simply generate the token using:
$token = $request->user()->createToken($request->token_name);
return ['token' => $token->plainTextToken];
What you need to make sure of is that you are using the trait HasApiTokens in the User Model:
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens;
}

Related

Graph API with ASP.NET Core Blazor WebAssembly

I would like to get information from Microsoft graph web API. I followed these instructions:
https://learn.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/graph-api?view=aspnetcore-5.0
The problem is that the variable "token" in the AuthenticateRequestAsync method is always null. It means that the Blazor app does not get the token.
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
var result = await TokenProvider.RequestAccessToken(
new AccessTokenRequestOptions()
{
Scopes = new[] { "https://graph.microsoft.com/User.Read" }
});
if (result.TryGetToken(out var token))
{
request.Headers.Authorization ??= new AuthenticationHeaderValue(
"Bearer", token.Value);
}
}
The Program.cs has the following code:
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddMsalAuthentication<RemoteAuthenticationState, RemoteUserAccount>(options =>
{
options.ProviderOptions.DefaultAccessTokenScopes.Add("https://graph.microsoft.com/User.Read");
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
});
builder.Services.AddGraphClient("https://graph.microsoft.com/User.Read");
In Index.razor I just add two lines of code I OnInitializedAsync method
var request = GraphClient.Me.Request();
user = await request.GetAsync();
I spent a lot of time to figure out what is the main issue but without success. I will appreciate any help.
Please imagine the single-page website. Usually, this kind of page has a "contact us" tab where is the contact form. If the user fills up the contact form then data have to be somehow sent to us. For this purpose, I tried to use MS graph API. When the user clicks the submit button, in the background the registration to my account will be created and an email will be sent to me. It means that the user is not aware of any registration procedure. – Samo Simoncic
For your app to be able to create users in a tenant, it needs to use an app only flow which requires a secret. We do not advise exposing app only flows of this nature, which can easily be exploited to create bogus users or overwhelm your tenant, open to the general public.
The best approach would be to take this registrations in a local DB, and then have a daemon app process them behind the scenes. Here is the sample where daemon console application is calling Microsoft Graph.
Not sure about the cause of the issue.
But I can make it work with the following code and configuration:
Program.cs
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
// Adds the Microsoft graph client (Graph SDK) support for this app.
builder.Services.AddMicrosoftGraphClient("https://graph.microsoft.com/User.Read");
// Integrates authentication with the MSAL library
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
options.ProviderOptions.DefaultAccessTokenScopes.Add("https://graph.microsoft.com/User.Read");
});
await builder.Build().RunAsync();
}
appsettings.json
{
"AzureAd": {
"Authority": "https://login.microsoftonline.com/exxxxx4e-bd27-40d5-8459-230ba2xxxxxb",
"ClientId": "7xxxxxx8-88b3-4c02-a2f8-0a890xxxxxx5",
"CallbackPath": "/signin-oidc",
"ValidateAuthority": "true",
"DefaultScopes": [
"openid",
"profile"
]
}
}
You can refer to the configuration and sample code here.
I have cloned your repo from the GitHub URL you posted in the comments.
There is no issue with the code to fetch the data from the Microsoft Graph API, the problem is that you have written the code of calling the API when the apps shows the index component before even the user logs in, you have to check if the user is logged in first and add a login button to the UI or you can add [Authorize] to the index page so it will redirect the user to Login before it shows the component and make the API and to implement that make sure to add the CascadingAuthenticationState and AuthorizeView to your App.razor as following
<CascadingAuthenticationState>
<Router AppAssembly="#typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="#routeData" DefaultLayout="#typeof(MainLayout)">
<NotAuthorized>
#if (!context.User.Identity.IsAuthenticated)
{
<a class="btn btn-success" href="/authentication/login">Login with Microsoft</a>
}
else
{
<p>You are not authorized to access this resource.</p>
}
</NotAuthorized>
</AuthorizeRouteView>
</Found>
<NotFound>
<LayoutView Layout="#typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
And then in your Index.razor add at the top the following line
#attribute [Authorize]
Then you launch the app if the user is not logged in, he/she will be asked to do so and then go to the Index component and make the API call which will succed then

laravel - Dynamic route group prefix as role

I want to use, User type in laravel route group prefix, after there login. But I am not getting a perfect way to do that.
eg: I have three user type-
1- admin
2- executive
3- user
I want to make a dynamic route prefix
eg:
1- admin/dashboard
2- executive/dashboard
3- user/dashboard
I am trying to do this with helper file
//Getting department name for url prefix helper.php
function routePrefix(){
$userDepartment = '';
if(Auth::user() != ''){
$dept_id = Auth::user()->department_id;
$userDepartment = Str::of(Department::where('id', $dept_id)->first()->department)->slug('-');
}
return $userDepartment;
}
Here i am unable to get auth details in helper file, cause of auth middleware in my route group
web.php
Route::group([
'middleware' => ['auth', 'accessControl'],
'prefix' => routePrefix(),
], function () {
Route::get('dashboard', 'UserController#index')->name('user.index')
})
Here every thing is working correctly when I am passing a static department id in helper,
But if I tried to get logged in user department I am getting the following error
ErrorException
Trying to get property 'department_id' of non-object

FirebaseUI React: allow user to sign up via email+password without providing their first/last name

I am using the FirebaseUI React auth component so users can log in via email + password.
const uiConfig = {
signInFlow: 'popup',
signInOptions: [
firebase.auth.EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD,
]
};
....
<FirebaseAuth uiConfig={uiConfig} firebaseAuth={firebase.auth()}/>
However, the registration form wants the user's first and last name.
I don't want the user to provide this information at the time of registration. How do I customize the component to remove the name input from the registration flow?
The setRequireName method seems to allow for this. Here is an example of the FirebaseUI demo application using setRequireName to enable/disable this UI element:
if (mUseEmailProvider.isChecked()) {
selectedProviders.add(new IdpConfig.EmailBuilder()
.setRequireName(mRequireName.isChecked())
.setAllowNewAccounts(mAllowNewEmailAccounts.isChecked())
.build());
}

Laravel: resetting password without getting redirect response

I am building an angular application and want to implement password reset. However, default laravel config doesn't appear to allow one to do this using purely XMLHttpRequest ($http.post) requests and responds with a 302 redirect.
I managed to get postLogin and postRegister to work without issuing redirects by implementing said methods in authController class and returning a json response, doing this overrides the default laravel implementation of said methods. No such luck with postEmail and it appears the method is not hit at all, I just get a 302 response back immediately.
Ideally, other than to check their E-mail, I don't want the user to leave the single page angular application at all.
So 1. User posts E-mail to postEmail -> Email with reset link or better 'reset code' is sent to E-mail address -> User then inputs the reset token code into the already open web app or if it can't be done, browse to reset password page opened in new tab.
I tried implementing postEmail method as such:
public function postEmail(Request $request)
{
$this->validate($request, ['email' => 'required|email']);
$response = Password::sendResetLink($request->only('email'), function (Message $message) {
$message->subject($this->getEmailSubject());
});
switch ($response) {
case Password::RESET_LINK_SENT:
return response()->json(['msg' => 'A reset link has been sent to your E-mail'], 200);
case Password::INVALID_USER:
return response()->json(['msg' => 'This E-mail cannot be found in our system'], 200);
}
}
Also, where is template for the E-mail with the reset link that laravel sends out ?
You can create a PasswordController within the App\Http\Controllers\Auth namespace to extend the password reset methods.
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\PasswordBroker;
use Illuminate\Foundation\Auth\ResetsPasswords;
class PasswordController extends Controller
{
use ResetsPasswords;
public function postEmail(Request $request)
{
}
}
To overwrite the email templates you can create a reminder.blade.php in the app/views/emails/auth directory, or change the location of the template file in the app/config/auth.php config.
while the accepted answer is completely valid, another solution without overriding the original notification class is as follows, ResetPassword provides a static method called createUrlUsing which accepts a Closure, So we can override the URL as something like the below:
use Illuminate\Support\Facades\Password;
use Illuminate\Auth\Notifications\ResetPassword;
...
$status = Password::sendResetLink(
['email' => $args['email']],
function ($user, $token) {
ResetPassword::createUrlUsing(function ($notifiable, $token) {
// This is where you override the URL, you can also take a look at
// the `url`, `action` and `route` functions in Laravel and skip
// `sprintf` if you prefer to stick to Laravel functions only.
return sprintf(
"%s/%s/?token=%s&email=%s",
config('your.optional.frontend_url'),
config('your.optional.password_reset'),
$token,
$notifiable->getEmailForPasswordReset(),
); // frontend_url/password_url/?token=TOKEN&email=EMAIL
});
return $user->notify(new ResetPassword($token));
}
);
// This is an optional way to handle the final response, you can convert it to
// JSON or ignore it.
return $status === Password::RESET_LINK_SENT
? ['status' => __($status)]
: throw new Error(__($status));
This piece of code should be placed at a new route to handle password reset requests instead of using the default Laravel one.

How to redirect to CodeIgniter controller using angular js

I am using CodeIgniter controller functions.
(example)
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Me extends CI_Controller {
public function __construct()
{
parent::__construct();
if (is_logged_in()){if (is_admin()) { redirect('login'); }}
else { redirect('login');}
}
public function change_password()
{
$id=$this->session->userdata['user_data']['id'];
$data = json_decode(file_get_contents("php://input"));
$my_data=array(
'pass'=>$data->pass,
'new_pass'=>$data->new_pass,
);
$result=$this->vanesh_model->change_pass($id,$my_data);
if($result==1)
{
$arr = array('msg' => "Password changed successfuly.", 'error' => '');
$jsn = json_encode($arr);
print_r($jsn);
}
else if($result==2)
{
$arr = array('msg' => "", 'error' => 'Old Password is Invalid');
$jsn = json_encode($arr);
print_r($jsn);
}
else if($result==3)
{
$arr = array('msg' => "", 'error' => 'Sorry, Password change failed');
$jsn = json_encode($arr);
print_r($jsn);
}
}
}
?>
I am afraid of using angular session services, so I want to maintain sessions with only CI. What I am doing in my application is add, update, delete only if he is logged in. And I am using information stored in session. Consider the situation, suppose, I am logged in and doing something, side by side: I destroy the session using browser tools. Now I am continuing with application (doing operations like: change password). I have/had maintained error messages, success messages, its ok. If session OFF, it gives error message. But instead of error messages, I want to redirect to LOGIN page(with page refresh).
Note: For CI Login controller, I didn't used angular js. I have used angularjs only after login.
If by opening new tab I destroy the session, and come back to application's tab: I am able to perform tasks(may be with errors,). If session is OFF I see this in Browser's console: http://localhost/ums/login
This is because of CI constructor(please look over the code).
You should separate angular and CI as much as possible, since both have view-controller it creates a mess. Instead you should have CI in a separate folder, call it api, for example, after that anything you will need from CI should be acessed from angular with ajax calls.
I made a small webapp a while ago and this seemed to be the best way to organize code.
Few updates have been made to angular since then so if there's a better way please let me know
Solved.
Used javascript function. Checking session by http request everytime. If response comes "1". Means redirect to login as:
/* function for checking logged-in and role */
function check_session()
{
$.get("servercontroller/check_session", function(data, status){
if(data=="1") /* error 1 => un-athorized user */
{
window.location.href="/login-page-url";
}
});
}

Resources