Im doing a expo app, with a login authentication, but my authUser is returning null and I could not find the reason
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((authUser) => {
console.log(authUser)
if (authUser) {
navigation.replace('Home');
}
})
return unsubscribe
}, [])
Can someone help?
I've tried use firebase.auth().onAuthStateChanged but no success :(
Related
I am using Laravel API as a backend for my react-native application. I want to get all the logged in user's data from the users table when he logs in.
I've tried several things but nothing has worked so far.
Here is my code:
Laravel api.php:
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});// i also tried this code.
Route::get('/user', function (Request $request) {
return $request->user();
});
ProfileScreen.js
const [user, setUser] = useState({});
const getUser = async () => {
try {
const token = await AsyncStorage.getItem('auth_token');
axios.get("/api/user").then(res => {
console.log(res.data)//this is logging nothing.
}).catch(e => console.log(e));
} catch (e) {
console.log('error' + e);
}
};
useEffect(() => {
getUser();
});
auth()->user() is a global helper, Auth::user() is a support facade,
and $request->user() uses http.
You can use any of them. For a quick test, try
Route::get('/test', function() {
return auth()->user();
})->middleware('auth:sanctum');
Be sure to send your token in a header like so:
Authorization: Bearer UserTokenHere
I am implementing firebase authentication to Nuxt js application and I am so close. The problem is I want to commit a vuext mutation inside firebase's default function onAuthStateChanged(). But when ever I load the page it shows the following error:
"Uncaught (in promise) TypeError: Cannot read properties of undefined (reading '$store')"
Can you guys please help me out with this problem.
Thanks.
import firebase from '#/plugins/firebase'
import {
getAuth,
signInWithEmailAndPassword,
onAuthStateChanged
} from "firebase/auth"
export const state = () => ({
user: null,
authIsReady: false
})
export const mutations = {
updateUser(state, payload) {
state.user = payload
console.log('user is updated', state.user)
},
setAuthIsReady(state, payload) {
state.authIsReady = payload
console.log(state.authIsReady)
}
}
export const actions = {
async signIn(context, {
email,
password
}) {
console.log('sign in action')
const res = await signInWithEmailAndPassword(getAuth(), email, password)
if (res) {
context.commit('updateUser', res.user)
} else {
throw new Error('could not complete sign in')
}
}
}
// this function is causing the problem
const unsub = onAuthStateChanged(getAuth(), (user) => {
this.$store.commit('updateUser', user)
unsub()
})
The firebase.js file that I'm importing "auth" from below, is just all the regular setting up Firebase in Nuxt stuff... and the important lines are:
const auth = getAuth()
export { auth }
Try the code below ... I have mine in a file named "fireauth.js" in the plugins folder (don't forget to import the "fireauth.js" file in your nuxt.config.js)
import {
auth
} from "~/plugins/firebase.js";
export default (context) => {
const {
store
} = context
return new Promise((resolve, reject) => {
auth.onAuthStateChanged((user) => {
if (user) {
return resolve(store.dispatch('onAuthStateChangedAction', user))
}
return resolve()
})
})
}
In your store/index.js file add the following async function in your actions setting:
async onAuthStateChangedAction(vuexContext, authUser) {
if (!authUser) { //in my case I'm just forcing user back to sign in page, only authorized users allowed//redirect from here this.$router.push({
path: '/signin',
})
}else {
//call your commits or do whatever you want to do
vuexContext.commit("setUser", authUser.email);
}
},
The first part of the code ensures that when the auth state changes in Firestore, this change is communicated to the action that you just created in the store. The second part of the code, the async function in the store accomplishes whatever you want it to do within the store.
I found something about this bug I explained at end;
Component codes
async fetch(){ await this.$store.dispatch('bots/getBots') },
computed: { ...mapState('bots', ['bots']) },
Store codes
export const state = () => {
return {
bots: []
}
}
export const mutations = {
UPDATE_BOTS(state, bots) {
state.bots = bots
}
}
export const actions = {
getBots({commit}) {
this.$axios.$get('url', {headers: {uid: '12345'}})
.then(res => {
commit('UPDATE_BOTS',res.robots)
})
.catch(e => {
console.log(e)
})
}
}
Issue: When moving between pages via nuxt-link data loads perfectly but when I reload the page bots state is empty...
Found Issue:
I use nuxt-auth and I had one plugin for checking status of axios request that if it was 401 unauthorized I logout user if he was loggedIn, So status undefined error was from here but I commented the plugin codes and I got other error from nuxt-auth that causes that problem I had So I related that issue in other question u can see it here:
Nuxt-Auth Bug: Looks for autherization in any get request that has headers config
It is the expected behavior. Vuex state is kept in memory and when you reload the page it gets purged.
Instead of this state
export const state = () => {
return {
bots: []
}
}
try this
export const state = () => ({
bots: []
})
I want to fetch data from my backend, change the 'isLoggedIn' state accordingly and therefore render a component conditionally. I just can't get my around it on how to structure it in a way that the component does not render twice.
First in my AuthForm component, there is a login function. It sets a httpOnly cookie for refreshing the JWT token, and and a JWT token directly on the headers.
const login = async () => {
try {
const response = await axios.post(props.baseUrl + "/auth/login", {
email,
password,
})
axios.defaults.headers.common[
"Authorization"
] = `Bearer ${response.data.token}`
dispatch(toggleLogin(true))
} catch ({ response }) {
console.log(response)
}
}
Since I want to display the Game UI instead of the AuthForm, I'm dispatching the toggleLogin action.
In the main component, i have a refreshToken function, that checks if the client got a httpOnly cookie and returns a new JWT if it is valid. So that the user is still logged in on a page refresh.
const Tamagotchi = () => {
const isLoggedIn = useSelector((state) => state.isLoggedIn)
const dispatch = useDispatch()
const refreshToken = async () => {
try {
const response = await axios.get(baseUrl + "/auth/refresh-token")
axios.defaults.headers.common[
"Authorization"
] = `Bearer ${response.data.token}`
dispatch(toggleLogin(true))
setTimeout(() => {
refreshToken()
}, response.data.expiresIn * 1000 - 500)
} catch ({ response }) {
if (response.status !== 201) {
dispatch(toggleLogin(false))
console.log("Not authorized")
}
}
}
useEffect(() => {
refreshToken()
})
return (
<TamagotchiWrapper>
<TamagotchiView>
{isLoggedIn ? <TamagotchiUI /> : <AuthForm />}
</TamagotchiView>
</TamagotchiWrapper>
)
}
If the user is logging in, or is refreshing the page, the Tamagotchi component gets rendered twice. The state gets changed because isLoggedIn changes and therefore it renders again and calling the useEffect hook again.
How to go about this?
Thanks in advance.
Try to wrap the refreshToken() call inside of useMemo instead of useEffect. useEffect works after the component prints the JSX and useMemo works before it.
useMemo(() => {
refreshToken()
}, []);
Please provide empty dependency array which means only render during initial loading.
useEffect(() => {
refreshToken()
}, [])
The solution was to pass refreshToken as a dependency in useEffect() and wrap the refreshToken() function in a useCallback Hook.
Then pass the refreshToken() function to my AuthForm component and call it on successful login.
This way the refreshToken function gets called correctly when opening the app to authenticate the user, and on successful login to be able to refresh the token.
I'm trying to implement an SSO react-admin login
Most of the react-admin examples a is simple username/password login and get token then store at storage. But for me, token will return from Auth Provider server and redirect to http://example.com/#/login?token=TOKEN, and make react-admin to parse the URL, and set token in localStorage. Then update React admin store to mark a user as "is logged in,"
but for me I failed to simulate logged in as a hook after validating token from app main js can you help me how to do that
A workaround like below is works for me, but this is quite dirty solution:
const url = window.location;
(() => {
if (localStorage.getItem("access_token") === "null" || localStorage.getItem("access_token") === "undefined") {
localStorage.removeItem("access_token");
}
})();
const access_token = () => {
if (localStorage.getItem("access_token")) {
return localStorage.getItem("access_token")
} else if (new URLSearchParams(url.search).get("access_token")) {
return new URLSearchParams(url.search).get("access_token")
}
}
localStorage.setItem("access_token", access_token());
export const authProvider = {
login: () => {
return Promise.resolve();
},
logout: () => {
localStorage.removeItem("access_token");
return Promise.resolve();
},
checkError: (status) => {
if (status.response.status === 401 || status.response.status === 403) {
localStorage.removeItem("access_token");
return Promise.reject();
}
return Promise.resolve();
},
checkAuth: () => {
return localStorage.getItem("access_token") ? Promise.resolve() : Promise.reject();
},
getPermissions: () => Promise.resolve(),
};
There is no login method call at all, just direct setting token to the localStorage and check with checkAuth method. Maybe, sombody will give better solution.