diff --git a/recordings/User_3768991250/will-not-be-logged-if-has-invalid-token_1301762210/recording.har b/recordings/User_3768991250/will-not-be-logged-if-has-invalid-token_1301762210/recording.har index a4d7605fa..e287b6cf6 100644 --- a/recordings/User_3768991250/will-not-be-logged-if-has-invalid-token_1301762210/recording.har +++ b/recordings/User_3768991250/will-not-be-logged-if-has-invalid-token_1301762210/recording.har @@ -8,11 +8,11 @@ }, "entries": [ { - "_id": "f0343691dcc48a40921887f4f58c55b6", + "_id": "4113b07f8435ac712a5761c5bc33aa90", "_order": 0, "cache": {}, "request": { - "bodySize": 692, + "bodySize": 428, "cookies": [], "headers": [ { @@ -28,7 +28,7 @@ { "_fromType": "array", "name": "content-length", - "value": "692" + "value": "428" }, { "_fromType": "array", @@ -56,7 +56,7 @@ "postData": { "mimeType": "application/json", "params": [], - "text": "[{\"operationName\":\"VerifyToken\",\"variables\":{\"token\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTUyMzk4OTcsImV4cCI6MTU5NTI0MDE5NywidG9rZW4iOiJxQ1Jia0dOMnpOT28iLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwidHlwZSI6ImFjY2VzcyIsInVzZXJfaWQiOiJWWE5sY2pveU1RPT0iLCJpc19zdGFmZiI6dHJ1ZX0.l-FnFDVmi5fASo7Uae2Emewu2pKyO2qLz7ZQl1fSzo41\"},\"query\":\"fragment User on User {\\n id\\n email\\n firstName\\n lastName\\n userPermissions {\\n code\\n name\\n __typename\\n }\\n avatar {\\n url\\n __typename\\n }\\n __typename\\n}\\n\\nmutation VerifyToken($token: String!) {\\n tokenVerify(token: $token) {\\n payload\\n user {\\n ...User\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}]" + "text": "[{\"operationName\":\"VerifyToken\",\"variables\":{\"token\":\"NotAToken\"},\"query\":\"fragment User on User {\\n id\\n email\\n firstName\\n lastName\\n userPermissions {\\n code\\n name\\n __typename\\n }\\n avatar {\\n url\\n __typename\\n }\\n __typename\\n}\\n\\nmutation VerifyToken($token: String!) {\\n tokenVerify(token: $token) {\\n payload\\n user {\\n ...User\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}]" }, "queryString": [], "url": "http://localhost:8000/graphql/" @@ -72,7 +72,7 @@ "headers": [ { "name": "date", - "value": "Tue, 21 Jul 2020 11:52:05 GMT" + "value": "Fri, 24 Jul 2020 09:02:43 GMT" }, { "name": "server", @@ -84,7 +84,7 @@ }, { "name": "access-control-allow-origin", - "value": "*" + "value": "http://localhost:9000" }, { "name": "access-control-allow-methods", @@ -94,6 +94,10 @@ "name": "access-control-allow-headers", "value": "Origin, Content-Type, Accept, Authorization" }, + { + "name": "access-control-allow-credentials", + "value": "true" + }, { "name": "content-length", "value": "89" @@ -103,14 +107,14 @@ "value": "nosniff" } ], - "headersSize": 314, + "headersSize": 374, "httpVersion": "HTTP/1.1", "redirectURL": "", "status": 200, "statusText": "OK" }, - "startedDateTime": "2020-07-21T11:52:05.050Z", - "time": 169, + "startedDateTime": "2020-07-24T09:02:43.587Z", + "time": 13, "timings": { "blocked": -1, "connect": -1, @@ -118,7 +122,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 169 + "wait": 13 } } ], diff --git a/recordings/User_3768991250/will-not-be-logged-in-if-doesn-t-have-valid-credentials_3719199657/recording.har b/recordings/User_3768991250/will-not-be-logged-in-if-doesn-t-have-valid-credentials_3719199657/recording.har index 4673d4895..fccbdb2d0 100644 --- a/recordings/User_3768991250/will-not-be-logged-in-if-doesn-t-have-valid-credentials_3719199657/recording.har +++ b/recordings/User_3768991250/will-not-be-logged-in-if-doesn-t-have-valid-credentials_3719199657/recording.har @@ -8,11 +8,11 @@ }, "entries": [ { - "_id": "29fb7ad4777c005f81fdfd957c1c81af", + "_id": "faa83118f90012a7303c655a14d89c0d", "_order": 0, "cache": {}, "request": { - "bodySize": 588, + "bodySize": 603, "cookies": [], "headers": [ { @@ -28,7 +28,7 @@ { "_fromType": "array", "name": "content-length", - "value": "588" + "value": "603" }, { "_fromType": "array", @@ -56,7 +56,7 @@ "postData": { "mimeType": "application/json", "params": [], - "text": "[{\"operationName\":\"TokenAuth\",\"variables\":{\"email\":\"admin@example.com\",\"password\":\"admin1\"},\"query\":\"fragment User on User {\\n id\\n email\\n firstName\\n lastName\\n userPermissions {\\n code\\n name\\n __typename\\n }\\n avatar {\\n url\\n __typename\\n }\\n __typename\\n}\\n\\nmutation TokenAuth($email: String!, $password: String!) {\\n tokenCreate(email: $email, password: $password) {\\n errors: accountErrors {\\n field\\n message\\n __typename\\n }\\n csrfToken\\n token\\n user {\\n ...User\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}]" + "text": "[{\"operationName\":\"TokenAuth\",\"variables\":{\"email\":\"admin@example.com\",\"password\":\"NotAValidPassword123!\"},\"query\":\"fragment User on User {\\n id\\n email\\n firstName\\n lastName\\n userPermissions {\\n code\\n name\\n __typename\\n }\\n avatar {\\n url\\n __typename\\n }\\n __typename\\n}\\n\\nmutation TokenAuth($email: String!, $password: String!) {\\n tokenCreate(email: $email, password: $password) {\\n errors: accountErrors {\\n field\\n message\\n __typename\\n }\\n csrfToken\\n token\\n user {\\n ...User\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}]" }, "queryString": [], "url": "http://localhost:8000/graphql/" @@ -72,7 +72,7 @@ "headers": [ { "name": "date", - "value": "Wed, 22 Jul 2020 09:21:11 GMT" + "value": "Fri, 24 Jul 2020 09:02:43 GMT" }, { "name": "server", @@ -84,7 +84,7 @@ }, { "name": "access-control-allow-origin", - "value": "*" + "value": "http://localhost:9000" }, { "name": "access-control-allow-methods", @@ -94,6 +94,10 @@ "name": "access-control-allow-headers", "value": "Origin, Content-Type, Accept, Authorization" }, + { + "name": "access-control-allow-credentials", + "value": "true" + }, { "name": "content-length", "value": "214" @@ -103,14 +107,14 @@ "value": "nosniff" } ], - "headersSize": 315, + "headersSize": 375, "httpVersion": "HTTP/1.1", "redirectURL": "", "status": 200, "statusText": "OK" }, - "startedDateTime": "2020-07-22T09:21:11.006Z", - "time": 363, + "startedDateTime": "2020-07-24T09:02:43.099Z", + "time": 426, "timings": { "blocked": -1, "connect": -1, @@ -118,7 +122,7 @@ "receive": 0, "send": 0, "ssl": -1, - "wait": 363 + "wait": 426 } } ], diff --git a/src/auth/link.ts b/src/auth/link.ts index 66c19a069..306ef036f 100644 --- a/src/auth/link.ts +++ b/src/auth/link.ts @@ -11,7 +11,7 @@ interface ResponseError extends ErrorResponse { }; } -export const invalidTokenLink = onError((error: ResponseError) => { +export const invalidateTokenLink = onError((error: ResponseError) => { if ( (error.networkError && error.networkError.statusCode === 401) || error.graphQLErrors?.some(isJwtError) @@ -34,6 +34,6 @@ export const tokenLink = setContext((_, context) => { }; }); -const link = invalidTokenLink.concat(tokenLink); +const link = invalidateTokenLink.concat(tokenLink); export default link; diff --git a/src/auth/utils.ts b/src/auth/utils.ts index cce76bc10..9ce9a6b23 100644 --- a/src/auth/utils.ts +++ b/src/auth/utils.ts @@ -1,7 +1,11 @@ +import { IMessageContext } from "@saleor/components/messages"; import { UseNotifierResult } from "@saleor/hooks/useNotifier"; import { commonMessages } from "@saleor/intl"; +import { ApolloError } from "apollo-client"; import { IntlShape } from "react-intl"; +import { isJwtError, isJwtExpiredError } from "./errors"; + export enum TOKEN_STORAGE_KEY { AUTH = "auth", CSRF = "csrf" @@ -36,9 +40,7 @@ export const setAuthToken = (auth: string, persist: boolean) => { export const removeTokens = () => { localStorage.removeItem(TOKEN_STORAGE_KEY.AUTH); - // localStorage.removeItem(TOKEN_STORAGE_KEY.CSRF); sessionStorage.removeItem(TOKEN_STORAGE_KEY.AUTH); - // sessionStorage.removeItem(TOKEN_STORAGE_KEY.CSRF); }; export const displayDemoMessage = ( @@ -49,3 +51,40 @@ export const displayDemoMessage = ( text: intl.formatMessage(commonMessages.demo) }); }; + +export async function handleQueryAuthError( + error: ApolloError, + notify: IMessageContext, + tokenRefresh: () => Promise, + logout: () => void, + intl: IntlShape +) { + if (error.graphQLErrors.some(isJwtError)) { + if (error.graphQLErrors.every(isJwtExpiredError)) { + const success = await tokenRefresh(); + + if (!success) { + logout(); + notify({ + status: "error", + text: intl.formatMessage(commonMessages.sessionExpired) + }); + } + } else { + logout(); + notify({ + status: "error", + text: intl.formatMessage(commonMessages.somethingWentWrong) + }); + } + } else if ( + !error.graphQLErrors.every( + err => err.extensions?.exception?.code === "PermissionDenied" + ) + ) { + notify({ + status: "error", + text: intl.formatMessage(commonMessages.somethingWentWrong) + }); + } +} diff --git a/src/hooks/makeQuery.ts b/src/hooks/makeQuery.ts index d5117469a..e67bf93f7 100644 --- a/src/hooks/makeQuery.ts +++ b/src/hooks/makeQuery.ts @@ -1,7 +1,6 @@ -import { isJwtError, isJwtExpiredError } from "@saleor/auth/errors"; -import { commonMessages } from "@saleor/intl"; -import { maybe, RequireAtLeastOne } from "@saleor/misc"; -import { ApolloError, ApolloQueryResult } from "apollo-client"; +import { handleQueryAuthError } from "@saleor/auth"; +import { RequireAtLeastOne } from "@saleor/misc"; +import { ApolloQueryResult } from "apollo-client"; import { DocumentNode } from "graphql"; import { useEffect } from "react"; import { QueryResult, useQuery as useBaseQuery } from "react-apollo"; @@ -48,37 +47,14 @@ function makeQuery( }, errorPolicy: "all", fetchPolicy: "cache-and-network", - onError: async (error: ApolloError) => { - if (error.graphQLErrors.some(isJwtError)) { - if (error.graphQLErrors.every(isJwtExpiredError)) { - const success = await user.tokenRefresh(); - - if (!success) { - user.logout(); - notify({ - status: "error", - text: intl.formatMessage(commonMessages.sessionExpired) - }); - } - } else { - user.logout(); - notify({ - status: "error", - text: intl.formatMessage(commonMessages.somethingWentWrong) - }); - } - } else if ( - !error.graphQLErrors.every( - err => - maybe(() => err.extensions.exception.code) === "PermissionDenied" - ) - ) { - notify({ - status: "error", - text: intl.formatMessage(commonMessages.somethingWentWrong) - }); - } - }, + onError: error => + handleQueryAuthError( + error, + notify, + user.tokenRefresh, + user.logout, + intl + ), skip, variables }); diff --git a/src/queries.tsx b/src/queries.tsx index 96c4f8b5d..3f7e039cb 100644 --- a/src/queries.tsx +++ b/src/queries.tsx @@ -1,15 +1,14 @@ -import { ApolloError, ApolloQueryResult } from "apollo-client"; +import { ApolloQueryResult } from "apollo-client"; import { DocumentNode } from "graphql"; import React from "react"; import { Query, QueryResult } from "react-apollo"; import { useIntl } from "react-intl"; -import { isJwtError, isJwtExpiredError } from "./auth/errors"; +import { handleQueryAuthError } from "./auth"; import useAppState from "./hooks/useAppState"; import useNotifier from "./hooks/useNotifier"; import useUser from "./hooks/useUser"; -import { commonMessages } from "./intl"; -import { maybe, RequireAtLeastOne } from "./misc"; +import { RequireAtLeastOne } from "./misc"; export interface LoadMore { loadMore: ( @@ -79,38 +78,15 @@ export function TypedQuery( skip={skip} context={{ useBatching: true }} errorPolicy="all" - onError={async (error: ApolloError) => { - if (error.graphQLErrors.some(isJwtError)) { - if (error.graphQLErrors.every(isJwtExpiredError)) { - const success = await user.tokenRefresh(); - - if (!success) { - user.logout(); - notify({ - status: "error", - text: intl.formatMessage(commonMessages.sessionExpired) - }); - } - } else { - user.logout(); - notify({ - status: "error", - text: intl.formatMessage(commonMessages.somethingWentWrong) - }); - } - } else if ( - !error.graphQLErrors.every( - err => - maybe(() => err.extensions.exception.code) === - "PermissionDenied" - ) - ) { - notify({ - status: "error", - text: intl.formatMessage(commonMessages.somethingWentWrong) - }); - } - }} + onError={error => + handleQueryAuthError( + error, + notify, + user.tokenRefresh, + user.logout, + intl + ) + } > {(queryData: QueryResult) => { const loadMore = (