React NextAuth credentials null and Auth Not Working - javascript

I get the following error:
here is my code:
return (
<>
{Object.values(providers).map((provider) => {
if (provider.id === "credentials") {
return null;
}
return (
<div key={provider.name}>
<Button
variant="outlined"
onClick={() => {
setAppLoading(true);
signIn(provider.id);
setAppLoading(false);
}}
className="w-full uppercase !transform-none mt-4"
>
<Image
height={24}
width={24}
src={`/logos/${provider.name}.svg` || "/logos/google.svg"}
alt={provider.name}
/>
<span className="ml-2 !text-[rgba(26, 26, 44, 0.5)]">
Sign in with {provider.name}
</span>
</Button>
</div>
);
})}
</>
);
};
If I silence the error by adding { providers !=== null && ... }, the page loads however,
the auth does not work at all, almost as if it is not getting fired
Here is the Form Button onSubmit, which gets called when I click it however, the signIn("credentials...}) doesn't fire
import { ClientSafeProvider, signIn } from "next-auth/client";
...
onSubmit={async (values, { setErrors }) => {
const { email, password } = values;
setAppLoading(true);
signIn("credentials", {
email,
password,
redirect: false,
}).then((res) => {
setErrors({ error: res?.error });
});
setAppLoading(false);
}}
...
and lastly, here is my [...nextauth].ts
import login from "features/auth/login";
import register from "features/auth/register";
import NextAuth from "next-auth";
import Providers from "next-auth/providers";
export default NextAuth({
providers: [
Providers.Credentials({
name: "Credentials",
credentials: {
name: { label: "Name", type: "text" },
email: { label: "Email", type: "text" },
password: { label: "Password", type: "password" },
},
async authorize(credentials, _req) {
const { name, email, password } = credentials;
alert("clicked");
console.log("CLICKEEEED!!!!!!!!!!!!!!");
if (typeof name === "undefined") {
return login(email, password);
}
return register(name, email, password);
},
}),
Providers.Google({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
],
pages: {
signIn: "/auth/signin",
signOut: "/auth/signout",
error: "/auth/error", // Error code passed in query string as ?error=
verifyRequest: "/auth/verify-request", // (used for check email message)
},
session: {
jwt: true,
maxAge: 30 * 24 * 60 * 60, // 30 days
},
});

Are you certain that you have provided valid GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in your .env.local file? This is the most common cause of your error. This would mean that next-auth did not provide you with providers, because of an error in the api.

Related

Uncaught (in promise) TypeError: type.trim is not a function

My login page was working fine, I did an update and this error appeared.
Uncaught (in promise) TypeError: type.trim is not a function
Login.vue
import { UserLogin } from "#/common/auth_apis";
import { notify } from "#/common/helpers";
import { CheckUserSubscription } from "#/common/subscription_apis";
export default {
data: () => ({
form: {}
}),
methods: {
login() {
UserLogin(this.form).then(res => {
if(res && res.data){
this.$store.dispatch('setToken', res.data.access_token);
this.$store.dispatch('setUserName', res.data.username);
this.$store.dispatch('setUserType', res.data.role);
this.$store.dispatch('setUserAvatar', res.data.avatar);
localStorage.setItem("logged", true);
let _type = res.data.role.trim();
if( _type == "1" || _type == "2") CheckUserSubscription();
this.$router.push({path: '/'});
notify('success', null, 'Inicia sesión correctamente');
}else{
notify('error', null, 'error de inicio de sesion');
}
})
},
gotoRecuperar(){
// if(!this.isManager) return;
this.$router.push('/recuperar/');
},
gotoRegistrar(){
// if(!this.isManager) return;
this.$router.push('/register/');
}
}
};
when executing I get the following error.
Uncaught (in promise) TypeError: type.trim is not a function
at Store.setUserType (index.js?4360:50)
at Array.wrappedActionHandler (vuex.esm.js?2f62:847)
at Store.dispatch (vuex.esm.js?2f62:512)
at Store.boundDispatch [as dispatch] (vuex.esm.js?2f62:402)
at eval (Login.vue?7463:70)
in the page index.js
import Vue from "vue";
import Vuex from "vuex";
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex);
export default new Vuex.Store({
plugins: [createPersistedState({
storage: window.sessionStorage,
})],
state: {
user_id: null,
user_name: null,
user_type: null,
user_avatar: null,
access_token: null,
},
mutations: {
setUserID (state, id) {
state.user_id = id
},
setUserName (state, name) {
state.user_name = name
},
setUserType (state, type) {
state.user_type = type
},
setUserAvatar (state, avatar) {
state.user_avatar = avatar
},
setToken (state, token) {
state.access_token = token
},
clearUserInfo (state) {
state.user_id = null
state.user_name = null
state.user_type = null
state.user_avatar = null
state.access_token = null
}
},
actions: {
setToken ({commit}, token) {
commit('setToken', token);
},
setUserName ({commit}, name) {
commit('setUserName', name.trim());
},
setUserType ({commit}, type) {
commit('setUserType', type.trim());
},
setUserAvatar ({commit}, avatar) {
commit('setUserAvatar', avatar ? avatar.trim() : null);
},
clear ({commit}){
commit('clearUserInfo');
}
},
getters: {
user: state => {
return {
id: state.user_id,
name: state.user_name,
type: state.user_type,
avatar: state.user_avatar
}
},
token: state => {
return state.access_token;
}
},
modules: {}
});
the return value of the service is as follows.
access_token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC93bGluaWkuY29tXC9hcHBzZXJ2aWNlXC9hcGlcL3VzdWFyaW8iLCJpYXQiOjE2MTM0NTQ0OTAsImV4cCI6MTYxMzU0MDg5MCwibmJmIjoxNjEzNDU0NDkwLCJqdGkiOiJZdUFOQVFkdDNoTDJ0UUZOIiwic3ViIjoiMDAwMDAwMDIiLCJwcnYiOiI1ODcwODYzZDRhNjJkNzkxNDQzZmFmOTM2ZmMzNjgwMzFkMTEwYzRmIn0.3uHqmQSCfQjdq1v74xbi39ime8SEs2zC2LxbF5llums"
avatar: "/images/perfil/1612847757.png"
role: 1
username: "VDIEG10"
I have seen in some posts that it could be a problem with the NPM version.
Thanks in advance for the help.
You can only call the trim method on strings. res.data.role is a Number and so res.data.role.trim is undefined.
setUserType({ commit }, type) {
commit('setUserType', type)
}

Vue js: compare elements in the array

in my code below i'm trying to check if the entered email is NOT exists in the API data this.users.email
but it giving me error: can't read email of undefined.However, when i console.log(this.users) i can see all my data , but when i console.log(this.users.email) it giving me undefined, any idea on how to solve it?
export default {
data() {
return {
error: "",
message:"",
users:[],
Reset: false,
login: {
email: "",
password: "",
},
SendEmail:{
email:"",
}
};
},
methods: {
Submit(){
try {
questionService.RequestResetPassword(this.SendEmail).then((response) => {
console.log(response);
});
}
catch (e) { if(!this.sendEmail.email.includes(this.users.email)){ //error here
this.error="enter an existing email";
}}
}
},
mounted: function () {
questionService.getAllUsers().then((jsonData) => {
this.users = jsonData.data.response;
console.log(this.users) // can appear properly
console.log(this.users.email) //undefined
})}
};

Vuetify form .$refs validate is not a function

Im getting Error in v-on handler: "TypeError: this.$refs.EmailMessage.validate is not a function on my form when I click on send in console as well as this.$refs.EmailMessage.validate is not a function.
I created a Mapactions where I commit the Payload to the emailjs server
I've tested $refs somewhere else and it does the same thing. could it be that Vuejs has a bug? or am I doing something silly?
My form in my Contact page
<v-form ref="EmailMessage" v-model="valid" lazy-validation>
<v-text-field
solo
:rules="[required]"
v-model="fd.name"
label=" Name & Surname"
name="nameSurname"
type="text"
required
></v-text-field>
<v-text-field
solo
:rules="emailRules"
v-model="fd.email"
label="E-mail address"
name="emailAddress"
required
></v-text-field>
<v-textarea
solo
v-model="fd.Message"
:rules="[required]"
label="Message"
name="Message"
required
></v-textarea>
<p class="text-right red--text ma-0 py-3" v-if="emailError">
{{ emailError }}
</p>
<v-btn
color="#212529"
dark
#click="validate()"
:loading="loading"
:disabled="!valid"
block
>SEND</v-btn
>
</v-form>
My method handling the send and reset of my contact form
<script>
import { mapState } from "vuex";
import { mapActions } from "vuex";
import emailjs from "emailjs-com";
export default {
data: () => ({
emailError: null,
valid: true,
loading: false,
required: (v) => !!v || "This field is required",
emailRules: [
(v) => !!v || "E-mail is required",
(v) => /.+#.+\..+/.test(v) || "E-mail must be valid",
],
///////////
fd: {
name: process.env.NODE_ENV == "development" ? "Test name" : null,
email: process.env.NODE_ENV == "development" ? "email#gmail.com" : null,
Message: process.env.NODE_ENV == "development" ? "Hello World" : null,
},
}),
methods: {
...mapActions(["sendMail"]),
validate() {
if (this.$refs[`EmailMessage`].validate()) {
this.loading = true;
emailjs
.send(
"gmail_service_id",
"ContactForm",
this.fd,
"userIDhere"
)
.then((result) => {
console.log("SUCCESS!", result.status, result.text);
this.loading = false;
this.resetForm();
})
.catch((e) => {
console.log("Error", e);
this.loading = false;
this.emailError = "Error while trying to send email";
});
}
},
resetForm() {
this.$refs[`EmailMessage`].reset();
},
contactImage: function (path) {
return require("#/" + path);
},
},
computed: {
...mapState("staticData", ["contact", "contactSocialMedia"]),
},
};
</script>
my actions in my store index.js
actions: {
sendMail: ({
commit
}, pl) => new Promise((resolve, reject) => {
if (pl.name) {
console.log('PL recieved: ', pl)
resolve('email is sent')
} else {
reject('email is not sent')
}
}),
},
I would really appreciate some help.
Got it to work!
I had a look at this example and gave it a try this.$refs[(“p” + index)].focus is not a function
problem was you need to add an array of 0 to the line where $refs are.
here are my methods under export default
methods: {
...mapActions(["sendMail"]),
validate() {
//Added [0] after email message
if (this.$refs[`EmailMessage`][0].validate()) {
this.loading = true;
emailjs
.send(
"gmail_service_id",
"ContactForm",
this.fd,
"InsertemailjsserviceIDhere"
)
.then((result) => {
console.log("SUCCESS!", result.status, result.text);
this.loading = false;
this.resetForm();
})
.catch((e) => {
console.log("Error", e);
this.loading = false;
this.emailError = "Error while trying to send email";
});
}
},
resetForm() {
//Added [0] after email message
this.$refs[`EmailMessage`][0].reset();
},
},

How to redirect user to home page if user is authentic i.e ID or PASSWORD is correct in vue.js using VUEX STORE state?

I am setting user authenticity in VUEX Store state if user id and password are valid. But how would I access this in my signIn.vue to redirect?
If user is valid then set VUEX store state i.e isUserAuthentic to true
For this I've used computed properties. to get user state i.e isUserAuthentic and work around in hasUserSignedIn in computed properties. I'm checking if user is authentic then redirect and return undefined from this computed properties. So that I can use this in HTML and doesn't affect HTML because I'm returning undefined from that computed properties.
It is working but that's not perfect/best practices.
SignIn.vue
<template>
<section>
<div class="form-wrapper">
//--------------------------------------USING COMPUTED PROPERTIES
{{ hasUserSignedIn }}
<input v-model="email"/>
<input v-model="password"/>
<button class="btn-signin" #click="submit()">
sign in
</button>
</div>
</section>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
data() {
email: '',
password: '',
},
methods: {
submit() {
if (this.email && this.password) {
this.$store.dispatch('signInUser', { email: this.email, password: this.password });
}
},
redirectTohome() {
this.$router.push({ path: '/home' });
},
},
computed: {
...mapGetters(['isUserAuthentic']),
//-----------------------------------------WORKAROUND COMPUTED PROPERTIES
hasUserSignedIn() {
if (this.isUserAuthentic) {
this.redirectTohome();
}
return undefined;
},
},
};
</script>
VUEX signin.js
import Vue from 'vue';
import axios from 'axios';
// const URL = 'http://localhost:3000';
const state = {
signInLoading: false,
isUserAuthentic: false,
};
const getters = {
isSignInLoading: (signInState) => signInState.signInLoading,
isUserAuthentic: (signInState) => signInState.isUserAuthentic,
};
const mutations = {
SET_SIGNIN_LOADING_STATUS(signInState, status) {
signInState.signInLoading = status;
},
SET_USER_AUTHENTICITY(signInState, isAuthentic) {
signInState.isUserAuthentic = isAuthentic;
},
};
const actions = {
async signInUser({ commit }, payload) {
// SET LOADING STATUS TRUE
commit('SET_SIGNIN_LOADING_STATUS', true);
try {
// AUTHORIZE USER WITH AXIOS
const response = await axios.post(`${URL}/api/v1/user/signin`, payload);
// IF USER IS AUTHENTIC, SET AUTHENTIC STATUS TO TRUE
if (response.status === 200) {
commit('SET_USER_AUTHENTICITY', true);
}
} catch (e) {
// SEND TOAST NOTIFICATION TO USER FOR INVALID REQUESTS
if (e.response && e.response.data.message) {
Vue.$toast(e.response.data.message, {
type: 'info',
timeout: 8000,
});
} else {
Vue.$toast('Something went wrong, Please try again.', {
type: 'error',
timeout: 8000,
});
}
}
// SET LOADING STATUS FALSE
commit('SET_SIGNIN_LOADING_STATUS', false);
},
};
export default {
state,
getters,
mutations,
actions,
};
You are pretty much spot on. The only thing I feel you should do is that you can wait for the promise of the store dispatch('signInUser') to resolve and check the state of isUserAuthentic. Something like this:
SignIn.vue
<script>
import { mapGetters } from 'vuex';
export default {
data() {
email: '',
password: '',
},
methods: {
async submit() { // use the 'async' keyword so that you can use await
if (this.email && this.password) {
await this.$store.dispatch('signInUser', { email: this.email, password: this.password }); // wait for the signInUser action to complete
if (this.isUserAuthentic) {
this.redirectTohome();
}
}
},
redirectTohome() {
this.$router.push({ path: '/home' });
}
},
},
computed: {
...mapGetters(['isUserAuthentic']), // mapState will be better here since you don't alter the state
},
};
</script>
<template>
...
{{ isUserAuthentic }}
...
</template>
Also, as an aside, I feel you should fire a commit i.e commit('SET_USER_AUTHENTICITY', false); when there's a failure. That's missing from your code.
Since you are returning the state as is, and not altering it, mapState will be better than mapGetters in your case.
I read the docs and I think WATCHERS are much better than COMPUTED in this particular case.
In this approach we don't have to use {{ hasUserSignedIn }} in HTML. Just watch the property and when it is true redirect to home.
watch: {
isUserAuthentic(val) {
if (val) {
this.redirectTohome();
}
},
},
If someone have better solution, You are more than welcome

Sharepoint Framework with reactjs and hellojs in Internet Explorer 11

I have a webpart with sharepoint framework and reactjs and i use hellojs --> hellojs
I do: npm install hellojs --save and all works fine in edge, chrome and firefox but i need this in Internet Explorer 11.
I try with a sample in js and html and works fine in internet explorer 11 but not in my sharepoint project. I have this:
import * as React from 'react';
import * as hello from 'hellojs';
import { Event } from '../interfaces/Event';
export class Authentication extends React.Component<{}, { sendEvent: boolean }> {
private refreshTokenInterval: number;
constructor(public props, public context) {
super(props, context);
this.state = {
sendEvent: true
};
}
public login(network) {
hello.init({
aad: {
name: 'Azure Active Directory',
oauth: {
version: 2,
auth: 'https://login.microsoftonline.com/tenant/oauth2/v2.0/authorize',
grant: 'https://login.microsoftonline.com/tenant/oauth2/v2.0/token'
},
// Authorization scopes
scope: {
// you can add as many scopes to the mapping as you want here
profile: 'Group.Read.All',
offline_access: ''
},
scope_delim: ' ',
login: (p) => {
if (p.qs.response_type === 'code') {
// Let's set this to an offline access to return a refresh_token
p.qs.access_type = 'offline_access';
}
},
base: 'https://www.graph.microsoft.com/v1.0/',
get: {
me: 'me'
},
xhr: (p) => {
if (p.method === 'post' || p.method === 'put') {
JSON.parse(p);
} else if (p.method === 'patch') {
hello.utils.extend(p.query, p.data);
p.data = null;
}
return true;
},
// Don't even try submitting via form.
// This means no POST operations in <=IE9
form: false
}
});
hello.init(
{
aad: 'clientId'
},
{
redirect_uri: 'my redirect',
//redirect_uri: 'https://localhost:4321/temp/workbench.html',
scope: 'Group.Read.All'
}
);
// By defining response type to code, the OAuth flow that will return a refresh token to be used to refresh the access token
// However this will require the oauth_proxy server
hello(network).login({ display: 'none' }).then(
(authInfo) => {
console.log(authInfo);
localStorage.setItem('logged', authInfo.authResponse.access_token);
localStorage.setItem('timeToRefresh', authInfo.authResponse.expires_in.toString());
this.props.setEvent(Event.GET_ALL_GROUPS);
this.setState({ sendEvent: false });
clearInterval(this.refreshTokenInterval);
this.refreshTokenInterval = window.setInterval(() => {
let timeToRefresh = Number(localStorage['timeToRefresh']) - 1;
localStorage.setItem('timeToRefresh', timeToRefresh.toString());
if (timeToRefresh <= 200) {
localStorage.clear();
sessionStorage.clear();
}
}, 1000);
},
(e) => {
console.error('Signin error: ' + e.error.message);
}
);
}
public componentDidMount() {
let logged = localStorage['logged'];
if (logged === undefined) this.login('aad');
else {
if (this.state.sendEvent) {
this.props.setEvent(null);
this.props.setEvent(Event.GET_ALL_GROUPS);
}
}
}
public render() {
return null;
}
/*private logout(network) {
// Removes all sessions, need to call AAD endpoint to do full logout
hello(network).logout({ force: true }, console.log).then(
function() {
console.log('Out');
},
function(e) {
console.error('Sign out error: ' + e.error.message);
}
);
}*/
}
And i call this class in a main class:
public render(): JSX.Element {
return (
<div className="row">
<div className="col-md-2" style={{ maxWidth: '250px' }}>
<LeftPanel setEvent={this.getEvent} />
</div>
<div className="col-md-10">
<Authentication setEvent={this.getEvent} />
<CenterPanel event={this.state.event} context={this.props.context} />
</div>
</div>
);
}
Console in internet explorer 11:
Solved!
cd "folder with the package.json"
npm install url-polyfill --save
import 'url-polyfill';

Categories