AWS-React: The specified key does not exist - reactjs

I made one react app. My app works as expected. This app's target is practice AWS-COGNITO. For Cognito validation I am using amazon-cognito-identity-js package. I made one helper function where I validate the Congnito. and reuse it in different component. I split my Nav bar into two components. From Congnito current user I made one callback function and use it in useEffect, and dependencies put the callback function, by default getAuthenticatedUser is null. I add condition where it fetch the data, if getAuthenticatedUser then redirect to signin and signup page. I deployed my app to s3 bucket and this the link. This app runs first time, When I refresh it then got error: 404 Not Found. I really don't know what is the issue and somehow the path react path get disappear. I share my code in code-sandbox.
This is my conditional path
import React from "react";
import SigninLinks from './SigninLinks';
import SignoutLinks from './SignoutLinks';
import useHandlder from '../configHandler/useHandler';
const Nav = () => {
const { getAuthenticatedUser } = useHandlder();
const Links = getAuthenticatedUser() === null ? <SignoutLinks /> : <SigninLinks />
return (
<nav className="nav-wrapper grey darken-3">
<div className="container">
<h2 className="brand-logo">Logo</h2>
{
Links
}
</div>
</nav>
);
};
export default Nav;
This is my handler functions
import React, { useCallback, useEffect } from 'react';
import { CognitoUserPool } from 'amazon-cognito-identity-js';
const Pool_Data = {
UserPoolId: "us-east-1_9gLKIVCjP",
ClientId: "629n5o7ahjrpv6oau9reo669gv"
};
export default function useHandler() {
const userPool = new CognitoUserPool(Pool_Data)
const getAuthenticatedUser = useCallback(() => {
return userPool.getCurrentUser();
},
[],
);
useEffect(() => {
getAuthenticatedUser()
}, [getAuthenticatedUser])
const signOut = () => {
return userPool.getCurrentUser()?.signOut()
}
return {
userPool,
getAuthenticatedUser,
signOut
}
};

It's paths issue. You get 404 on /path not in root /. Check S3 settings for hosting static sites. On S3 make sure static website hosting is enabled:
You react app loads on /index.html JavaScript then redirects and takes over the path. You need S3 to resolve path to index.html, then it will work.

Related

In Next.js 13 with turbopack, how do I access cookies without getServerSideProps?

I have an app that persists some values in a cookie. I know that there are other tools such as useState, useContext, etc... but this particular app works with a library that stores information in a jwt so I have to read certain values by fetching the jwt. I am porting the app from next.js 12 (with webpack) to next.js 13 (with turbopack).
I've already ported the app structurally to fit the app style routing of next.js 13. My pages all go in their individual folders with sub layouts WITHIN the app directory, and I have a master layout and homepage directly in the app directory.
The old code for my protected page in next.js 12 looked like this:
protected.tsx
import type { NextPage } from 'next';
import { GetServerSideProps } from 'next';
import { useContext } from 'react';
//#ts-ignore
import Cookies from 'cookies';
const Protected: NextPage = (props: any) => {
if (!props.authorized) {
return (
<h2>Unauthorized</h2>
)
} else {
return (
<div className="max-w-md">
<h1 className="font-bold">This is the Protected Section</h1>
</div>
)}
}
export const getServerSideProps: GetServerSideProps = async ({ req, res, query }) => {
const { id } = query
const cookies = new Cookies(req, res)
const jwt = cookies.get('<MY TOKEN NAME>')
if (!jwt) {
return {
props: {
authorized: false
},
}
}
const { verified } = <MY TOKEN SDK INSTANCE>.verifyJwt({ jwt })
return {
props: {
authorized: verified ? true : false
},
}
}
export default Protected
I have this page moved into it's own directory now.
"getServerSideProps" isn't supported in Next.js 13 https://beta.nextjs.org/docs/data-fetching/fundamentals. The docs say "previous Next.js APIs such as getServerSideProps, getStaticProps, and getInitialProps are not supported in the new app directory." So how would I change my code to work in Next.js 13?
P.S. I know what it looks like but this cookie IS NOT HANDLING USER AUTHENTICATION. I understand that someone could alter the cookie and gain access to the protected page. This is just a small piece of a larger app with other security mechanisms that I have in place.
import { cookies } from "next/headers";
this is next/headers.js cookie function
function cookies() {
(0, _staticGenerationBailout).staticGenerationBailout('cookies');
const requestStore = _requestAsyncStorage.requestAsyncStorage && 'getStore' in _requestAsyncStorage.requestAsyncStorage ? _requestAsyncStorage.requestAsyncStorage.getStore() : _requestAsyncStorage.requestAsyncStorage;
return requestStore.cookies;
}
this is making a request to the client side to get the cookie. In app directory, you are on the server and you can write this inside the component.
const cookie = cookies().get("cookieName")?.value
you can access to your cookie via "cookies-next" library.
pnpm i cookies-next
check this out : https://www.npmjs.com/package/cookies-next

How Do I Call An Authenticated HTTP Trigger Google Cloud Function Via A Next.js (with Typescript) App?

I created a Google Cloud Platform account, and made a simple hello_world type Python "Cloud Function" that just spits out some simple text. I made this function "HTTP" accessible and only able to be called/authenticated by a "Service Account" that I made for the purpose of calling this very function. I generated a key for this "Service Account" and downloaded the json file for the key.
The problem is that I can't find any documentation on how to call this function with my service account in a next.js app. I tried this:
import React from 'react';
import { Button } from 'react-bootstrap';
import { GoogleAuth } from 'google-auth-library';
const projectId = 'gtwitone';
const keyFilename = '/Users/<myusername>/path/to/cloudfunction/credentials.json';
class Middle extends React.Component {
handleClick() {
console.log('this is:', this);
}
// This syntax ensures `this` is bound within handleClick. // Warning: this is *experimental* syntax. handleClick = () => { console.log('this is:', this); }
/* async listFunctions() {
const [functions] = await client.listFunctions();
console.info(functions);
} */
async runGoogleCloudFunctionTest() {
// Define your URL, here with Cloud Run but the security is exactly the same with Cloud Functions (same underlying infrastructure)
const url = "https://us-central1-<projectname>.cloudfunctions.net/<functionname>"
//Example with the key file, not recommended on GCP environment.
const auth = new GoogleAuth({keyFilename: keyFilename})
//Create your client with an Identity token.
const client = await auth.getIdTokenClient(url);
const res = await client.request({url});
console.log(res.data);
}
render() {
return (
<div className="col-md-12 text-center">
<Button variant='primary' onClick={this.runGoogleCloudFunctionTest}>
Click me
</Button>
</div>
);
}
}
export default Middle;
But I got this error in my terminal:
<myusername>#<mycomputername> <thisnextjsappdirectory> % yarn dev
yarn run v1.22.17
$ next dev
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
wait - compiling...
event - compiled client and server successfully in 267 ms (124 modules)
wait - compiling / (client and server)...
wait - compiling...
error - ./node_modules/google-auth-library/build/src/auth/googleauth.js:17:0
Module not found: Can't resolve 'child_process'
Import trace for requested module:
./node_modules/google-auth-library/build/src/index.js
./components/Middle.tsx
./pages/index.tsx
https://nextjs.org/docs/messages/module-not-found
Native Node.js APIs are not supported in the Edge Runtime. Found `child_process` imported.
Could not find files for / in .next/build-manifest.json
Could not find files for / in .next/build-manifest.json
^C
<myusername>#<mycomputername> <thisnextjsappdirectory> %
I know that this is problem with server side rendering in my Next.js app and people recommend using a client side package like this https://github.com/google/google-api-javascript-client. But google-api-javascript-client doesn't have any documentation on authenticating with a .json credentials file instead of an API KEY which I do not have.
In short how do I get my app to work and run the Google Cloud function with a .json credentials file for am authenticated service account?
I fixed it by simply moving the GoogleAuth api call to the pages/api route.
pages/api/google.ts
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from "next"
import { GoogleAuth } from "google-auth-library"
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const url = process.env.FUNCTION_URL as string
//Example with the key file, not recommended on GCP environment.
const auth = new GoogleAuth({ keyFilename: process.env.KEYSTORE_PATH })
//Create your client with an Identity token.
const client = await auth.getIdTokenClient(url)
const result = await client.request({ url })
console.log(result.data)
res.json({ data: result.data })
}
components/Middle.tsx
import React from "react"
import { Button } from "react-bootstrap"
class Middle extends React.Component {
handleClick() {
console.log("this is:", this)
}
// this talks with /pages/api/google
async imCallingAnAPI() {
const result = await fetch("/api/google")
console.log({ result })
}
render() {
return (
<div className="col-md-12 text-center">
<Button variant="primary" onClick={this.imCallingAnAPI}>
Click me
</Button>
</div>
)
}
}
export default Middle
pages/index.tsx
import type { NextPage } from 'next'
import Header from '../components/Header';
import Footer from '../components/Footer';
import Middle from '../components/Middle';
const Home: NextPage = () => {
return (
<><main className='d-flex flex-column min-vh-100'>
<Header />
<br></br>
<br></br>
<Middle />
</main>
<footer>
<Footer />
</footer>
</>
)
}
export default Home
I think that next.js has trouble loading GoogleAuth in a component. I'm not 100% sure why, but I think it has to do with next.js not knowing exactly how to handle GoogleAuth with server-side rendering.

Shopify App/Nextjs: How to get RoutePropagator to work?

How do I get route propagation working in a Nextjs Shopify app?
I'm building a Shopify App scaffolded with the CLI and have issues with routing using the Nextjs router. The standard embedded app implementation does not update the URL so a RoutePropagator component is needed.
I implemented Shopify's RoutePropagator but got the error TypeError: Cannot read properties of undefined (reading 'pathname')
Then I found this implementation which works for updating the URL, but runs into a really strange issue for Dynamic Urls.
Whenever a user navigated to a dynamic url, the url would update with [id] in the url. Gif example:
Narrowing it down, the below snipped causes the above dynamic url issue:
import { useEffect, useContext } from "react";
import Router, { useRouter } from "next/router";
import { Context as AppBridgeContext } from "#shopify/app-bridge-react";
import { Redirect } from "#shopify/app-bridge/actions";
import { RoutePropagator as ShopifyRoutePropagator } from "#shopify/app-bridge-react";
const RoutePropagator = () => {
const router = useRouter();
const { route } = router;
const appBridge = React.useContext(AppBridgeContext);
// Subscribe to appBridge changes - captures appBridge urls
// and sends them to Next.js router. Use useEffect hook to
// load once when component mounted
useEffect(() => {
appBridge.subscribe(Redirect.Action.APP, ({ path }) => {
Router.push(path);
});
}, []);
return appBridge && route ? (
<ShopifyRoutePropagator location={route} app={appBridge} />
) : null;
};
export default RoutePropagator;
How do I get the URL to update as the user navigates through the application for all urls (including dynamic urls)?
Use
const { asPath } = router
instead of route and it's gonna work!

NextJS Redirect not work if user come from browser url bar

Already three days struggling to solve this problem so any help appreciated.
I have a simple component for check token from localStorage:
import Router from 'next/router';
const Blog = _ => {
const token = localStorage.getItem("token");
useEffect(_ => {
if(!token){
Router.push('/')
}
}, [])
}
This will work if we have a code like this:
<Link href="/blog">Blog</Link>
Then when you click blog you will be redirect to "/".
But if you type in browser url bar /blog and push enter you will not redirect to main page "/".
UPD:There is no token in localStorage
There are two problems with your code:
There is no return statement in the functional component. React throws an error if there is nothing returned.
If you type '/blog' in the browser, Nextjs throws an error, as the code is first run on the server( the server doesn't have a local storage - Error: localStorage is not defined). To resolve this you can do one of two things -
check whether the code is executing on the server or the client and then handle accordingly
move localStorage.getItem inside componentDidMount( or hooks equivalent).
import Router from "next/router";
import { useEffect } from "react";
const Blog = _ => {
useEffect(_ => {
const token = localStorage.getItem("token");
if (!token) {
Router.push("/");
}
}, []);
return <p>This is a blog</p>;
};
export default Blog;

how to Redirect to another page in next.js based on css media query?

im brand new to Next.js and i have the following situation. i want to redirect the user to the route /messages if he type route /messages/123 based on css media query so if he is mobile we will not redirect and if he in browser then redirect .
i have tried the following code
import React, { useLayoutEffect } from 'react';
import { useRouter, push } from 'next/router';
import useMediaQuery from '#material-ui/core/useMediaQuery';
import Layout from '../components/Customer/Layout/Layout';
import Chat from '../components/Customer/Chat/Chat';
const Messages = () => {
const { pathname, push } = useRouter();
const matches = useMediaQuery('(min-width:1024px)');
useLayoutEffect(() => {
console.log('I am about to render!');
if (matches && pathname === '/messages') {
console.log('match!');
push('/');
}
}, [matches, pathname, push]);
return (
<Layout currentURL={pathname}>
<Chat />
</Layout>
);
};
export default Messages;
the problem is the component render twice before redirect
But You should probably be using useEffect since you are not trying to do any DOM manipulations or calculations.
useLayoutEffect: If you need to mutate the DOM and/or DO need to perform measurements
useEffect: If you don't need to interact with the DOM at all or your DOM changes are unobservable (seriously, most of the time you should use this).
You should see immediate action.
Edit:
You can use Next JS getInitialProps to check the request headers and determine if the request if from mobile or desktop then redirect from there.
getInitialProps({ res, req }) {
if (res) {
// Test req.headers['user-agent'] to see if its mobile or not then redirect accordingly
res.writeHead(302, {
Location: '/message'
})
res.end()
}
return {}
}

Resources