React hooks and getStaticProps - authentication

I want to access hooks from getStaticProps to get the accessToken of the logged user which is saved in AuthContext. but this is impossible
I am using getStaticProps of Nextjs to pre-render pages, this is an example :
export async function getStaticProps() {
const result = await axios.get("http://127.0.0.1:5000/track/landing-tracks-for-admin");
return {
props: {
tracks: result.data,
},
revalidate: 5,
};
}
the problem is that this request needs the user accesToken which I can get from useAuth
import useAuth from "../../hooks/useAuth";
but when I try to call it in getStaticProps like this : const auth = useAuth();
I get this error
React Hook "useAuth" is called in function "getStaticProps" that is neither a React function component nor a custom React Hook function
any other alternatives ?

I guess you cannot authenticate the user like this. Please follow the documentation on Nextjs for authentication.
There is also an example repository for static page authentication using with-iron-session.
I suggest that you implement the user Authentication the nextjs way since you are using nextjs

Related

FirebaseAuth with SvelteKit on +page.ts load

I have a SvelteKit app and am using Firebase and Node to do simple Google SSO auth. I am using an API that requires the IDToken of the currently signed in user to authenticate requests. Ideally I'd like to use the +page.ts load function to load in the data, something like this:
export const load = (async () => {
// Get user, token
const auth = getAuth();
const user = auth.currentUser;
const token = await user?.getIDToken();
if (!token) throw error(401, "Could not authenticate");
// Use token to get data needed to load page
const data = api.requestData(token);
return { data };
}) satisfies PageLoad;
export const ssr = false;
The issue is that user is always null when this function executes. I imagine this is because this is called before the page loads and Firebase hasn't had a way to access the session and get the current user.
My question is, what approach do I take to solve this without simply requesting the data after the page is rendered? Is there a way to authenticate the user server side? Thanks so much.

404 error calling GET API from a shopify theme-extension

I'm new to shopify development, and can't figure out how to call an authenticated API from a shopify theme-extension. Essentially, I'm trying to make a theme extension, where one of the functionalities is that when a checkbox is clicked, an API that counts the number of products is called.
I have a working api that gets the product count, and in web>index.js, I have set-up the end-point:
app.get("/api/products/count", async (_req, res) => {
const countData = await shopify.api.rest.Product.count({
session: res.locals.shopify.session,
});
res.status(200).send(countData);
});
Under web>frontend>hooks, I have the authenticated hooks set-up as shown below. I've tested that if I call the "api/products/count" API from one of the web pages using useAppQuery, it works as expected, and returns the product count.
import { useAuthenticatedFetch } from "./useAuthenticatedFetch";
import { useMemo } from "react";
import { useQuery } from "react-query";
export const useAppQuery = ({ url, fetchInit = {}, reactQueryOptions }) => {
const authenticatedFetch = useAuthenticatedFetch();
const fetch = useMemo(() => {
return async () => {
const response = await authenticatedFetch(url, fetchInit);
return response.json();
};
}, [url, JSON.stringify(fetchInit)]);
return useQuery(url, fetch, {
...reactQueryOptions,
refetchOnWindowFocus: false,
});
};
In my theme extension code, I've added an event listener to the checkbox which calls getProductCount. In getProductCount, I want to call /api/products/count:
import { useAppQuery } from "../../../web/frontend/hooks";
export const getProductCount = (product) => {
const {
data,
refetch: refetchProductCount,
isLoading: isLoadingCount,
isRefetching: isRefetchingCount,
} = useAppQuery({
url: "/api/products/count",
reactQueryOptions: {
onSuccess: () => {
setIsLoading(false);
},
},
});
}
However, when I run locally and click the checkbox, it returns a 404 error trying to find useAppQuery. The request URL is https://cdn.shopify.com/web/frontend/hooks. It seems like the authentication isn't working because that URL looks incorrect.
Am I missing a step that I need to do in order to call an authenticated API from a theme-extension?
I thought the issue was just the import path for useAppQuery but I've tried different paths, and they all return the same 404 issue.
If you want a hot tip here. In your theme App extension, you do not actually need to make an API call to get a product count. In your theme app extension, you can just use Liquid, and dump the product count out to a variable of your choice, and use the count, display the count, do whatever.
{{ shop.product_count }}
Of course, this does not help you if you need other storefront API calls in your theme App extension, but whatever. In my experience, I render the API Access Token I need in my theme app extension, and then making my Storefront API calls is just a fetch().
The only time I would use authenticated fetch, is when I am doing embedded App API calls, but that is a different beast from a theme app extension. In there, you do not get to make authenticated calls as the front-end is verboten for those of course. Instead you'd use App Proxy for security.
TL:DR; Storefront API calls with a token should not fail with a 404 if you call the right endpoint. You can use Storefront API inside a theme app extension. Inside a theme app extension, if you need backend Admin API access, you can use App Proxy calls.

Is the function "signInWithPopup" from firebase supported on Expo?

I am trying to implement an authentication login method through Azure AD with Firebase on my Expo app.
Here is an extraction of my code, which looks exactly like the Firebase documentation:
const signInWithMicrosoft = () => {
const auth = initializeAuth(firebaseApp);
signInWithPopup(auth, provider)
.then((result) => {
const credential = OAuthProvider.credentialFromResult(result);
const accessToken = credential.accessToken;
const idToken = credential.idToken;
navigation.navigate("Home")
})
.catch((error) => {
// Handle error.
});
}
When pressing the button to activate the function, the following error message shows up:
TypeError: (0, _auth.signInWithPopup) is not a function. (In '(0, _auth.signInWithPopup)(auth, provider)', '(0, _auth.signInWithPopup)' is undefined)
I tried importing the functions as:
import { signInWithPopup } from "firebase/auth"
and
import { signInWithPopup } from "firebase/compat/auth"
And neither of them seem to work.
Is there any way I can get this function to work, or the solution would be going another way around? I don't know if functions such as SignInWithPopup and SignInWithRedirect are supported in Expo, since it is a Mobile application.
If you have any tip, clue or information on using firebase auth methods in a Expo app, please share below and I will be very happy to read it and comment on.

using redis in getServerSideProps results in error net.isIP is not a function

Correct me if I am wrong but getServerSideProps is used to pre-render data on each render? If I use the standard redis npm module in getServerSideProps I get the error net.isIP is not a function. From what I have researched this is due to the client trying to use the redis functions.
I am trying to create an application to where session data is saved in a redis key based on a cookie token. Based on the user Id a database is called and renders data to the component. I can get the cookie token in getServerSideProps but I I run client.get(token) I get the error net.isIP is not a function at runtime.
Am I not using getServerSideProps correctly or should I be using a different method / function? I am new to the whole Next.js world. I appreciate the help.
If I use the same functionality in an /api route everything works correctly.
import util from 'util';
import client from '../libs/redis' // using 'redis' module
// ... my component here
export async function getServerSideProps(context) {
const get = util.promisify(client.get).bind(client);
const name = await get('mytoken') // error `net.isIP is not a function`
return {
props: {
name
},
}
}
// redis.js
const redis = require("redis");
const client = redis.createClient();
client.on("error", function(error) {
console.error(error);
});
module.exports = client
I upgraded to next version 10.0.6 from 9.3 and I do not receive the error anymore.

React Native App Authentication with Instagram API

I've been trying to build a react native app that requires users to authenticate with their Instagram account. The Instagram API has a authorisation link and perhaps the only way to display that in an app would be through 'WebView' and so I used that.
The authentication workflow runs smoothly and then my server even gets the access token and user-id. But the problem is how to send this access token back to the app? I've used express-js for the 'redirect-uri' and so the WebView makes request to app.get() handler. In order to send response to same client on which the connection is opened, we must use res.send(). This would send the response to WebView, let's say I capture that using 'injectedJavaScript' but this javascript runs within WebView and so its unable to access react-native variables. In the event of a correct access-token, how would I ever navigate away from the WebView?
Any solutions to the above problems would be greatly appreciated. I suspect that there might even be problems with this approach(in my choice of WebView for this purpose, etc.), so a change of approach even entirely would also be of help. All I want is to authenticate the app users with Instagram and get my project going. Thanks a lot.
If you are using Expo, you can use AuthSessions to accomplish this (https://docs.expo.io/versions/latest/sdk/auth-session). The exact way to do it depends on whether you are using a managed workflow or a bare workflow, etc., but for managed workflow you can do the following:
Go to the Facebook Developer's console, go to your app, and add the Instagram Basic Display product.
Under Instagram Basic Display, under Valid OAuth Redirect URIs, use https://auth.expo.io/#your-expo-username/your-project-slug (project slug is in your app.json file)
On the same FB Developer page, add an Instagram tester profile and then follow the steps to authenticate that user.
In your project, install expo install expo-auth-session and import it into your Component
Also install expo-web-browser
Code your component like so:
import React, { useEffect } from 'react';
import { Button, Platform, Text, TouchableOpacity, View } from 'react-native';
import * as WebBrowser from 'expo-web-browser';
import { useAuthRequest, makeRedirectUri } from 'expo-auth-session';
WebBrowser.maybeCompleteAuthSession(); // <-- will close web window after authentication
const useProxy = Platform.select({ web: false, default: true });
const client_id = 9999999999999;
const redirect_uri = "https://auth.expo.io/#your-expo-username/your-project-slug";
const scope = "user_profile,user_media";
const site = "https://api.instagram.com/oauth/authorize?client_id=" + client_id + "&redirect_uri=" + redirect_uri + "&scope=" + scope + "&response_type=code&state=1";
const discovery = { authorizationEndpoint: site }
const GetInstagram = () => {
const [request, response, promptAsync] = useAuthRequest({
redirectUri: makeRedirectUri({
useProxy,
native: redirect_uri
}),
scopes: [scope],
clientId: client_id
}, discovery);
useEffect(() => {
if (response?.type === 'success') {
const { code } = response.params; <--- the IG code will be returned here
console.log("code : ", code);
}
}, [response]);
return (
<View>
<TouchableOpacity onPress={ () => promptAsync({useProxy,windowFeatures: { width: 700, height: 600 }}) }>
<Text>Connect Your Instagram</Text>
</TouchableOpacity>
</View>
)
}
export default GetInstagram;
One way to accomplish this is via using deeplink. I don't think it's the best practice though.
The response from the WebView will be sent to the redirect URL you've previously setup after successful authentication. Please set the redirect URL to your app. For example, on iOS if you have URL Scheme as "myapp123" then, anytime you open your browser and type myapp123://.. it will open your app and your app should be able to get response sent from the instagram.