[GraphQL error]: Authentication hook unauthorized this request
Closed this issue · 3 comments
I followed frontend tutorial graphql with react https://hasura.io/learn/graphql/react/introduction/.
And I get authentication error with token I get with useAccessToken.
Base code I used is 698f187.
Error message is "[GraphQL error]: Authentication hook unauthorized this request " at TodoPrivateList.js:66.
When I hard code jwt like below that is gotten at https://hasura.io/learn/graphql/graphiql, I can query in localhost web site with npm start.
Why I get authentication error with token I get with useAccessToken? How can I handle token?
const createApolloClient = (authToken) => {
console.log(`authToken is ${authToken}`)
return new ApolloClient({
link: new HttpLink({
uri: 'https://hasura.io/learn/graphql',
headers: {
Authorization: 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik9FWTJSVGM1UlVOR05qSXhSRUV5TURJNFFUWXdNekZETWtReU1EQXdSVUV4UVVRM05EazFNQSJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLWRlZmF1bHQtcm9sZSI6InVzZXIiLCJ4LWhhc3VyYS1hbGxvd2VkLXJvbGVzIjpbInVzZXIiXSwieC1oYXN1cmEtdXNlci1pZCI6ImF1dGgwfDYyZGYyN2E3ZGMwMTBhYjg3YTFlMmRiYSJ9LCJuaWNrbmFtZSI6ImtoMDQxMiIsIm5hbWUiOiJraDA0MTJAZ21haWwuY29tIiwicGljdHVyZSI6Imh0dHBzOi8vcy5ncmF2YXRhci5jb20vYXZhdGFyLzI2ZmMzZThmNTVlMjIwM2UzOTgzMzQyZmYwMzUyZmM1P3M9NDgwJnI9cGcmZD1odHRwcyUzQSUyRiUyRmNkbi5hdXRoMC5jb20lMkZhdmF0YXJzJTJGa2gucG5nIiwidXBkYXRlZF9hdCI6IjIwMjQtMDctMjFUMDg6Mjk6MTIuODYyWiIsImlzcyI6Imh0dHBzOi8vZ3JhcGhxbC10dXRvcmlhbHMuYXV0aDAuY29tLyIsImF1ZCI6IlAzOHFuRm8xbEZBUUpyemt1bi0td0V6cWxqVk5HY1dXIiwiaWF0IjoxNzIxNTUxNDc4LCJleHAiOjE3MjE1ODc0NzgsInN1YiI6ImF1dGgwfDYyZGYyN2E3ZGMwMTBhYjg3YTFlMmRiYSIsImF0X2hhc2giOiJLcUNDay04T192ZjVaNWRDdjdXMGhnIiwic2lkIjoiMVNVUl9iUDFpcy1aNktKd1NGMmY5WGc2Rk9kYlFtQTEiLCJub25jZSI6IlQ3QWU0YktzTTlYX2VBeS1aT0xMLlowTGZ0MzRNU3FpIn0.hoSkaLMAjFeycQB7yHGEOQUWvpZd2e4CR72B-Hv3iMBgQtWc5t0uXqZZmDYYPQxpD30ZrLVtytv0XI_qc8zQLdc_B759VCUfah2hQ_sxifwYntRUV41ZdyGFNPw_zqQa9hSF6npFHXRQrnff7EHmvDEKL8YSGrOq1zMDhkpBN72ZCZQjmwUT3swABA51KB4J6ZlKYhPodq9GoOSPzxmYwsvWiO2nvoj7wJFDlfX6aiNRGai3a9lypCEPHo-vSLcD9gUXMrdsi-aeuCmPoHpyiWThNeCklprFaPaO4yJSCFECGLCOqX3JFhC5NILNK7ZUQVyHkHRHxkbjgK7VYx4AhA'
}
}),
cache: new InMemoryCache(),
});
};
Diff patch is below.
diff --git a/tutorials/frontend/react-apollo-hooks/app-boilerplate/src/components/App.js b/tutorials/frontend/react-apollo-hooks/app-boilerplate/src/components/App.js
index 2199664..c88f7d4 100644
--- a/tutorials/frontend/react-apollo-hooks/app-boilerplate/src/components/App.js
+++ b/tutorials/frontend/react-apollo-hooks/app-boilerplate/src/components/App.js
@@ -1,4 +1,4 @@
-import React from "react";
+import React, {useState} from "react";
import { useAuth0 } from "@auth0/auth0-react";
import Header from "./Header";
@@ -9,9 +9,26 @@ import OnlineUsersWrapper from "./OnlineUsers/OnlineUsersWrapper";
import useAccessToken from "../hooks/useAccessToken";
+import { ApolloClient, ApolloProvider, InMemoryCache, HttpLink } from '@apollo/client';
+
+const createApolloClient = (authToken) => {
+ console.log(`authToken is ${authToken}`)
+ return new ApolloClient({
+ link: new HttpLink({
+ uri: 'https://hasura.io/learn/graphql',
+ headers: {
+ Authorization: `Bearer ${authToken}`
+ }
+ }),
+ cache: new InMemoryCache(),
+ });
+};
+
+
const App = () => {
const idToken = useAccessToken();
const { loading, logout } = useAuth0();
+ const [client] = useState(createApolloClient(idToken));
if (loading) {
return <div>Loading...</div>;
@@ -20,25 +37,28 @@ const App = () => {
if (!idToken) {
return <Login />;
}
+
return (
- <div>
- <Header logoutHandler={logout} />
- <div className="row container-fluid p-left-right-0 m-left-right-0">
- <div className="row col-md-9 p-left-right-0 m-left-right-0">
- <div className="col-md-6 sliderMenu p-30">
- <TodoPrivateWrapper />
- </div>
- <div className="col-md-6 sliderMenu p-30 bg-gray border-right">
- <TodoPublicWrapper />
- </div>
- </div>
- <div className="col-md-3 p-left-right-0">
- <div className="col-md-12 sliderMenu p-30 bg-gray">
- <OnlineUsersWrapper />
- </div>
+ <ApolloProvider client={client}>
+ <div>
+ <Header logoutHandler={logout} />
+ <div className="row container-fluid p-left-right-0 m-left-right-0">
+ <div className="row col-md-9 p-left-right-0 m-left-right-0">
+ <div className="col-md-6 sliderMenu p-30">
+ <TodoPrivateWrapper />
+ </div>
+ <div className="col-md-6 sliderMenu p-30 bg-gray border-right">
+ <TodoPublicWrapper />
+ </div>
+ </div>
+ <div className="col-md-3 p-left-right-0">
+ <div className="col-md-12 sliderMenu p-30 bg-gray">
+ <OnlineUsersWrapper />
+ </div>
+ </div>
+ </div>
</div>
- </div>
- </div>
+ </ApolloProvider>
);
};
diff --git a/tutorials/frontend/react-apollo-hooks/app-boilerplate/src/components/Todo/TodoPrivateList.js b/tutorials/frontend/react-apollo-hooks/app-boilerplate/src/components/Todo/TodoPrivateList.js
index f1d43bc..cf84d9f 100644
--- a/tutorials/frontend/react-apollo-hooks/app-boilerplate/src/components/Todo/TodoPrivateList.js
+++ b/tutorials/frontend/react-apollo-hooks/app-boilerplate/src/components/Todo/TodoPrivateList.js
@@ -1,26 +1,21 @@
import React, { useState, Fragment } from "react";
-
import TodoItem from "./TodoItem";
import TodoFilters from "./TodoFilters";
+import {gql, useQuery} from '@apollo/client'
+const GET_MY_TODOS = gql`
+query getMyTodos {
+ todos(where: { is_public: { _eq: false} }, order_by: { created_at: desc }) {
+ id
+ title
+ created_at
+ is_completed
+ }
+}`;
const TodoPrivateList = props => {
const [state, setState] = useState({
filter: "all",
clearInProgress: false,
- todos: [
- {
- id: "1",
- title: "This is private todo 1",
- is_completed: true,
- is_public: false
- },
- {
- id: "2",
- title: "This is private todo 2",
- is_completed: false,
- is_public: false
- }
- ]
});
const filterResults = filter => {
@@ -32,11 +27,12 @@ const TodoPrivateList = props => {
const clearCompleted = () => {};
- let filteredTodos = state.todos;
+ const {todos} = props
+ let filteredTodos = todos
if (state.filter === "active") {
- filteredTodos = state.todos.filter(todo => todo.is_completed !== true);
+ filteredTodos = todos.filter(todo => todo.is_completed !== true);
} else if (state.filter === "completed") {
- filteredTodos = state.todos.filter(todo => todo.is_completed === true);
+ filteredTodos = todos.filter(todo => todo.is_completed === true);
}
const todoList = [];
@@ -61,4 +57,30 @@ const TodoPrivateList = props => {
);
};
-export default TodoPrivateList;
+const TodoPrivateListQuery = ()=> {
+ const { loading, error, data } = useQuery(GET_MY_TODOS)
+ if(loading) {
+ return <div>Loading...</div>
+ }
+ if (error) {
+ console.error(`[GraphQL error]: ${error.message}`);
+ if (error.graphQLErrors) {
+ error.graphQLErrors.forEach(({ message, locations, path }) =>
+ console.error(
+ `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
+ )
+ );
+ }
+ if (error.networkError) {
+ console.error(`[Network error]: ${error.networkError}`);
+ }
+ if (error.message.includes("Authentication hook unauthorized this request")) {
+ return <div>Authentication Error! Please log in again.</div>;
+ }
+ return <div>Error!</div>;
+ }
+ return <TodoPrivateList todos={data.todos}/>;
+}
+
+export default TodoPrivateListQuery;
+export {GET_MY_TODOS}
TodoPrivateList.js
import React, { useState, Fragment } from "react";
import TodoItem from "./TodoItem";
import TodoFilters from "./TodoFilters";
import {gql, useQuery} from '@apollo/client'
const GET_MY_TODOS = gql`
query getMyTodos {
todos(where: { is_public: { _eq: false} }, order_by: { created_at: desc }) {
id
title
created_at
is_completed
}
}`;
const TodoPrivateList = props => {
const [state, setState] = useState({
filter: "all",
clearInProgress: false,
});
const filterResults = filter => {
setState({
...state,
filter: filter
});
};
const clearCompleted = () => {};
const {todos} = props
let filteredTodos = todos
if (state.filter === "active") {
filteredTodos = todos.filter(todo => todo.is_completed !== true);
} else if (state.filter === "completed") {
filteredTodos = todos.filter(todo => todo.is_completed === true);
}
const todoList = [];
filteredTodos.forEach((todo, index) => {
todoList.push(<TodoItem key={index} index={index} todo={todo} />);
});
return (
<Fragment>
<div className="todoListWrapper">
<ul>{todoList}</ul>
</div>
<TodoFilters
todos={filteredTodos}
currentFilter={state.filter}
filterResultsFn={filterResults}
clearCompletedFn={clearCompleted}
clearInProgress={state.clearInProgress}
/>
</Fragment>
);
};
const TodoPrivateListQuery = ()=> {
const { loading, error, data } = useQuery(GET_MY_TODOS)
if(loading) {
return <div>Loading...</div>
}
if (error) {
console.error(`[GraphQL error]: ${error.message}`);
if (error.graphQLErrors) {
error.graphQLErrors.forEach(({ message, locations, path }) =>
console.error(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
)
);
}
if (error.networkError) {
console.error(`[Network error]: ${error.networkError}`);
}
if (error.message.includes("Authentication hook unauthorized this request")) {
return <div>Authentication Error! Please log in again.</div>;
}
return <div>Error!</div>;
}
return <TodoPrivateList todos={data.todos}/>;
}
export default TodoPrivateListQuery;
export {GET_MY_TODOS}App.js
import React, {useState} from "react";
import { useAuth0 } from "@auth0/auth0-react";
import Header from "./Header";
import Login from "./Auth/Login";
import TodoPrivateWrapper from "./Todo/TodoPrivateWrapper";
import TodoPublicWrapper from "./Todo/TodoPublicWrapper";
import OnlineUsersWrapper from "./OnlineUsers/OnlineUsersWrapper";
import useAccessToken from "../hooks/useAccessToken";
import { ApolloClient, ApolloProvider, InMemoryCache, HttpLink } from '@apollo/client';
const createApolloClient = (authToken) => {
console.log(`authToken is ${authToken}`)
return new ApolloClient({
link: new HttpLink({
uri: 'https://hasura.io/learn/graphql',
headers: {
Authorization: `Bearer ${authToken}`
}
}),
cache: new InMemoryCache(),
});
};
const App = () => {
const idToken = useAccessToken();
const { loading, logout } = useAuth0();
const [client] = useState(createApolloClient(idToken));
if (loading) {
return <div>Loading...</div>;
}
if (!idToken) {
return <Login />;
}
return (
<ApolloProvider client={client}>
<div>
<Header logoutHandler={logout} />
<div className="row container-fluid p-left-right-0 m-left-right-0">
<div className="row col-md-9 p-left-right-0 m-left-right-0">
<div className="col-md-6 sliderMenu p-30">
<TodoPrivateWrapper />
</div>
<div className="col-md-6 sliderMenu p-30 bg-gray border-right">
<TodoPublicWrapper />
</div>
</div>
<div className="col-md-3 p-left-right-0">
<div className="col-md-12 sliderMenu p-30 bg-gray">
<OnlineUsersWrapper />
</div>
</div>
</div>
</div>
</ApolloProvider>
);
};
export default App;Hi @kiitosu - The access token is being set using the following snippet here -
const getAccessToken = async () => {
const { audience, scope } = AUTH_CONFIG;
try {
const accessToken = await getAccessTokenSilently({
audience,
scope,
});
setIdToken(accessToken);
} catch (e) {
console.log(e.message);
}
};I would start debugging there. Quick caveat: The tutorial is using older versions of Auth0 SDK, so I would double-check if it is using the right one since newer ones may have breaking changes.
Meanwhile, I will try running it from my side to see what could be wrong.
Hi @kiitosu , I faced the same issue, which got resolved after using useMemo in place of useState for the client in below code:
const idToken = useAccessToken();
- const [client] = useState(createApolloClient(idToken));
+ const client = useMemo(() => {
+ if (!idToken) return null;
+ return createApolloClient(idToken);
+ }, [idToken]);
Reason: idToken was coming null initially and createApolloClient was getting called with null instead of the actual idToken.
@salonijain3112
Thank you very much for your answer!
I haven’t tried your suggestion yet because I lost the code I was working on.
But I will close this issue as your answer is correct!