When the app is launching for the sign in page, an error is occurring that relates to the authorized domains:
Cross-origin redirection to http://developers.google.com/ denied by Cross-Origin Resource Sharing policy: Origin capacitor://localhost is not allowed by Access-Control-Allow-Origin. Status code: 301
When I try to add capacitor://localhost to the list of authorized domains, it throws the error A valid domain name is required (e.g. 'myapp.com')
My authentication code both has a listener:
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, async (userInfo) => {
setUser(userInfo);
if (userInfo === null) {
localStorage.clear();
history.push("/login");
} else {
const token = await userInfo.getIdToken(true);
history.push("/home");
localStorage.setItem("AuthToken", `Bearer ${token}`);
}
});
return unsubscribe;
}, [user, history]);
and the sign in function:
export const signIn = async (email, password) => {
try {
await setPersistence(auth, browserLocalPersistence);
const userCredential = await signInWithEmailAndPassword(
auth,
email,
password
);
const user = userCredential.user;
const token = await user.getIdToken(true);
localStorage.setItem("AuthToken", `Bearer ${token}`);
return { user, token };
} catch (error) {
return { error: error.message };
}
};
I have seen some answers that might suggest it has to do with the Firebase Auth SDK having issues with capacitor because it is meant for a web app instead of mobile apps. However, there has not been very clear answers as to how I can confirm if that is the problem or how to solve it.
The solution was to implement this when using the firebase auth object
function whichAuth() {
let auth;
if (Capacitor.isNativePlatform()) {
auth = initializeAuth(app, {
persistence: indexedDBLocalPersistence,
});
} else {
auth = getAuth(app);
}
return auth;
}
export const auth = whichAuth();
It looks like you are trying to redirect to the Google Developer website from an app that is running on capacitor://localhost. This error is occurring because the browser is blocking the redirect due to a security feature called the "same-origin policy".
Also solution can be this:
function whichAuth() {
let auth;
if (Capacitor.isNativePlatform()) {
auth = initializeAuth(app, {
persistence: indexedDBLocalPersistence,
});
} else {
auth = getAuth(app);
}
return auth;
}
export const auth = whichAuth();
Related
After the user log into my application using Auth0, I'm getting other user settings from another api, however, this call does not seem to work, in fact it doesn't seem to like me adding the access_token from auth0.
I always end up with an error of: Uncaught (in promise) Error: Invalid hook call. Hooks can only be called inside of the body of a function component.
The code that is called after login in:
export default observer(function LoginMenu() {
const { currentUserStore: { login }} = useStore();
const { loginWithRedirect, isAuthenticated, logout } = useAuth0();
useEffect(() => {
if (isAuthenticated) {
login()
}
}, [isAuthenticated])
const handleLogin = async () => {
await loginWithRedirect({
prompt: "login",
appState: {
returnTo: "/callback",
},
});
}
....
})
Login function:
login = async () => {
this.loading = true;
try {
console.log("Calling API to get currentUser");
var user = await agent.CurrentUserApi.get();
console.log("currentUser: ", user);
} catch(error) {
runInAction(() => this.loading = false);
throw error;
}
}
Agent interceptor:
axios.interceptors.request.use(config => {
const { getAccessTokenSilently } = useAuth0();
config.headers = config.headers ?? {};
const token = getAccessTokenSilently();
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config;
})
From everything I can see, the issue is related to how the interceptor is working, without the interceptor the api call is made, however, without a access token, so the call fails to authenticate.
I'm trying to implement google sign in in my expo using expo-auth-session,
When I click on my gmail to sign in, I'm redirected to this screen saying "Something went wrong when trying to finish signing in. Please close this screen to go back to the app".
//Google auth code:
import * as Google from 'expo-auth-session/providers/google';
const [request, response, promptAsync] = Google.useAuthRequest({
expoClientId: config.google.expoClientId,
redirectUri: config.google.redirectUri,
});
React.useEffect(() => {
//Handle google login
console.log(response)
if (response?.type === 'success') {
const { authentication } = response;
}
}, [response]);
//Button that calls the google sign in
<Button iconName={'google'} iconPressed={() => promptAsync({useProxy: true})} />
If someone is trying this now.
You can Follow This https://www.youtube.com/watch?v=hmZm_jPvWWM
In the code given in this video
replace promptAsync({useProxy: false, showInRecents: true}) => promptAsync()
I ended up using expo-google-app-auth, for some reason that I'm yet to figure out, you have to use host.expo.exponent as your package name and bundle identifier in the google developer console for this library to work.
Code:
import { Alert } from 'react-native';
import * as Google from 'expo-google-app-auth'
const GoogleLogin = async () => {
//Get those keys from the google developer console
const { iosClientId, androidClientId } = config.google
const { type, user } = await Google.logInAsync({
iosClientId,
androidClientId,
});
if (type === 'success') {
/* `accessToken` is now valid and can be used to get data from the Google API with HTTP requests */
return { email: user.email, id: user.id }
} else {
Alert.alert("Google login error.")
}
}
export default GoogleLogin;
I think you can try like this
import * as Google from 'expo-auth-session/providers/google';
import * as WebBrowser from 'expo-web-browser';
WebBrowser.maybeCompleteAuthSession();
....
const [request, response, promptAsync] = Google.useAuthRequest({
androidClientId: config.androidClientId,
iosClientId: config.iosClientId,
expoClientId: config.expoClientId,
scopes: config.scopes,
});
useEffect(() => {
if (response?.type === 'success') {
const { authentication } = response;
getGoogleUser((authentication as any).accessToken)
}
}, [response]);
const getGoogleUser = async (accessToken: string) => {
try{
const response = await fetch('https://www.googleapis.com/userinfo/v2/me', {
headers: { Authorization: `Bearer ${accessToken}`}
});
const user = response.json()
if (user?.email) {
const { email, name } = user; // you will get more data in the user object
.......
}
}
catch(error){
console.log('GoogleUserReq error: ', error);
}
}
return (
<View>
<Button
onPress={() => promptAsync() }
/>
</View>
);
I have created a web app with Firebase and React.js and implemented sign-in with Google. I then tried to implement GoogleOneTapSignin and the one-tap-sign-in UI is working successfully because I used the react-google-one-tap-login npm package.
If may react app I have a function that listens for AuthStateChange and then either registers the user if they are new or sign in them if they are already a member and also updates the state if they logged. out.
Now that I have implemented google-one-tap-login, I was expecting the onAuthSTaetChanged function to be triggered if a user signs in using the google-one-tap-login but it is not the case.
Below is the part of my App.js code that handles the user auth.
const classes = useStyles();
const dispatch = useDispatch();
const alert = useSelector(state => state.notification.alert);
// Handling Google-one-tap-signin
useGoogleOneTapLogin({
onError: error => console.log(error),
onSuccess: response => {
console.log(response);
const credential = provider.credential(response);
auth.signInWithCredential(credential).then(result => {
const {
user
} = result;
console.log(user);
});
},
googleAccountConfigs: {
client_id: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
}
});
//Handling firebase authentification
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(async user => {
// If there is a user create the user profile and update useState
if (user) {
// createUserProfile function creates the user profile in firestore if they are new
const userRef = await createUserProfileDocument(user);
userRef.onSnapshot(snapshot => {
const doc = snapshot.data();
dispatch(
setUser({
id: snapshot.id,
...doc
})
);
});
} else {
dispatch(setUser(null));
}
});
return () => {
unsubscribe();
};
}, [dispatch]);
I tried to implement the solution suggested by the 2nd answer in this StackOverflow question but I get the error below on the console. when I use google-one-tap-sign-in. Remember I am not using the FirebaseUi library. So far my application only uses the sign in with Google
t {
code: "auth/argument-error",
message: "credential failed: must provide the ID token and/or the access token.",
a: null
}
a: null
code: "auth/argument-error"
message: "credential failed: must provide the ID token and/or the access token."
The ID token required by Firebase's signInWithCredential function exists within the credential property of the response object. Here is a sample function below using Firebase V8.
// firebase V8
function handleCredentialResponse(response) {
if (response) {
const cred = auth.GoogleAuthProvider.credential(response.credential);
// Sign in with credential from the Google user.
return auth().signInWithCredential(cred);
}
}
Firebase v9
// firebase V9
import { getAuth, GoogleAuthProvider, signInWithCredential } from "firebase/auth";
const auth = getAuth();
function handleCredentialResponse(response) {
if (response) {
const cred = GoogleAuthProvider.credential(response.credential)
// Sign in with credential from the Google user.
return signInWithCredential(auth, cred);
}
}
The response param is a credential response returned from the Google one-tap function callback.
google?.accounts.id.initialize({
client_id: your-google-app-client-id.apps.googleusercontent.com,
callback: handleCredentialResponse,
});
google?.accounts.id.prompt((notification) => {
console.log(notification);
});
I have an issue sending a JWT token to the server and using it to authorize access in load handlers. I am using Firebase on the client for authentication. When logged in (onAuthStateChanged), I send a POST request with the token to the /api/login endpoint:
export async function post(req) {
const idToken = req.headers['authorization']
try {
const token = await firebase().auth().verifyIdToken(idToken)
req.locals.user = token.uid
} catch (e) {
console.log(e)
return {
status: 500,
body: 'forbidden',
}
}
return {
status: 200,
body: 'ok',
}
}
In hooks.js:
export function getSession(request) {
return {
user: request.locals.user
}
}
export async function handle({ request, resolve }) {
const cookies = cookie.parse(request.headers.cookie || '')
request.locals.user = cookies.user
const response = await resolve(request)
response.headers['set-cookie'] = `user=${request.locals.user || ''}; Path=/; HttpOnly`
return response
}
In load methods:
export async function load({ session }) {
if (!session.user) {
return {
status: 302,
redirect: '/start'
}
}
// ...
}
All of this works fine except that any client-side navigation after a login is rejected because session.user is still undefined. When navigating by typing the URL in the browser, it works correctly and after that the client-side navigation also works.
Any ideas why and what to do?
I have solved this by adding a browser reload on whichever page the user lands on after logging in. The snippet for the reload on the client side handling on a successful response from the login API endpoint looks like this
if (sessionLoginResponse?.status === "success") {
await signOut(auth);
window.history.back();
setTimeout(() => {
window.location.reload();
}, 10);
}
I am trying to log in a user with Google in my React/Firebase app. I've followed a tutorial on youtube (https://www.youtube.com/watch?v=umr9eNbx3ag) but the results are different. When I click the Log In button, I get redirected to Google, choose an account and then get redirected to my site.
It seems as my 'if' statement never runs, auth.currentUser never evaluates to true.
This is my Firebase file
firebase.initializeApp(firebaseConfig)
export const firestore = firebase.firestore()
export const auth = firebase.auth()
export const provider = new firebase.auth.GoogleAuthProvider()
export const signInWithGoogle = () => auth.signInWithRedirect(provider)
export const signOut = () => auth.signOut()
export default firebase
This is my log in component
import { auth, signInWithGoogle, signOut } from '../../Firebase/Firebase'
const LoginOrRegister = () => {
const { username, setUsername, idToken, setIdToken } = useContext(Context)
useEffect(() => {
auth.onAuthStateChanged(async nextUser => {
if (auth.currentUser) {
setIdToken(await auth.currentUser.getIdToken())
setUsername(auth.currentUser.displayName)
} else {
setIdToken(null)
}
})
}, [])
return (
<div>
<LogInForm>
<button onClick={signInWithGoogle}> Log in with Google </button>
</div>
)
Since you are using signInWithRedirect you need to make use of auth.getRedirectResult() instead of auth.onAuthStateChanged as you are actually navigating away from the app and coming back in
Below code will work or you.
useEffect(() => {
auth
.getRedirectResult()
.then(function(result) {
console.log(result);
if (result.credential) {
// This gives you a Google Access Token. You can use it to access the Google API.
var token = result.credential.accessToken;
setToken(token);
// ...
}
// The signed-in user info.
var user = result.user;
console.log(user);
setData(user);
})
.catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// The email of the user's account used.
console.log(errorCode, errorMessage);
// ...
});
}, []);
You can find the reference documentation here