Handle token refreshing
This commit is contained in:
parent
765953c9a8
commit
d23202bf00
15 changed files with 220 additions and 134 deletions
|
@ -8,11 +8,11 @@
|
||||||
},
|
},
|
||||||
"entries": [
|
"entries": [
|
||||||
{
|
{
|
||||||
"_id": "5a18fed13283ef12aa42d45d206a87bd",
|
"_id": "ec3f8ec4f0f88fc421dc0d46281d4515",
|
||||||
"_order": 0,
|
"_order": 0,
|
||||||
"cache": {},
|
"cache": {},
|
||||||
"request": {
|
"request": {
|
||||||
"bodySize": 572,
|
"bodySize": 587,
|
||||||
"cookies": [],
|
"cookies": [],
|
||||||
"headers": [
|
"headers": [
|
||||||
{
|
{
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
{
|
{
|
||||||
"_fromType": "array",
|
"_fromType": "array",
|
||||||
"name": "content-length",
|
"name": "content-length",
|
||||||
"value": "572"
|
"value": "587"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"_fromType": "array",
|
"_fromType": "array",
|
||||||
|
@ -56,33 +56,33 @@
|
||||||
"postData": {
|
"postData": {
|
||||||
"mimeType": "application/json",
|
"mimeType": "application/json",
|
||||||
"params": [],
|
"params": [],
|
||||||
"text": "[{\"operationName\":\"TokenAuth\",\"variables\":{\"email\":\"admin@example.com\",\"password\":\"admin\"},\"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 token\\n errors: accountErrors {\\n field\\n message\\n __typename\\n }\\n user {\\n ...User\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}]"
|
"text": "[{\"operationName\":\"TokenAuth\",\"variables\":{\"email\":\"admin@example.com\",\"password\":\"admin\"},\"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": [],
|
"queryString": [],
|
||||||
"url": "http://localhost:8000/graphql/"
|
"url": "http://localhost:8000/graphql/"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"bodySize": 1749,
|
"bodySize": 1830,
|
||||||
"content": {
|
"content": {
|
||||||
"mimeType": "application/json",
|
"mimeType": "application/json",
|
||||||
"size": 1749,
|
"size": 1830,
|
||||||
"text": "[{\"data\": {\"tokenCreate\": {\"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTUzMzk3NDIsImV4cCI6MTU5NTM0MDA0MiwidG9rZW4iOiJxQ1Jia0dOMnpOT28iLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwidHlwZSI6ImFjY2VzcyIsInVzZXJfaWQiOiJWWE5sY2pveU1RPT0iLCJpc19zdGFmZiI6dHJ1ZX0.hZ2hTVOU8h7fMf--Qm891DpV1hssicEaQShyy4sPKXM\", \"errors\": [], \"user\": {\"id\": \"VXNlcjoyMQ==\", \"email\": \"admin@example.com\", \"firstName\": \"\", \"lastName\": \"\", \"userPermissions\": [{\"code\": \"MANAGE_APPS\", \"name\": \"Manage apps\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_CHECKOUTS\", \"name\": \"Manage checkouts\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_DISCOUNTS\", \"name\": \"Manage sales and vouchers.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_GIFT_CARD\", \"name\": \"Manage gift cards.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_MENUS\", \"name\": \"Manage navigation.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_ORDERS\", \"name\": \"Manage orders.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PAGES\", \"name\": \"Manage pages.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PLUGINS\", \"name\": \"Manage plugins\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PRODUCTS\", \"name\": \"Manage products.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_SETTINGS\", \"name\": \"Manage settings.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_SHIPPING\", \"name\": \"Manage shipping.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_STAFF\", \"name\": \"Manage staff.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_TRANSLATIONS\", \"name\": \"Manage translations.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_USERS\", \"name\": \"Manage customers.\", \"__typename\": \"UserPermission\"}], \"avatar\": null, \"__typename\": \"User\"}, \"__typename\": \"CreateToken\"}}}]"
|
"text": "[{\"data\": {\"tokenCreate\": {\"errors\": [], \"csrfToken\": \"oQ3yHRrBRRtQNVuJgn4D6Txh3aPWC8fl91XMcA2bukbgkdUotAEAJbAcCvTsXn3Z\", \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTU0MDk1ODUsImV4cCI6MTU5NTQwOTU5MCwidG9rZW4iOiJDM1NrMmtMUlZ1UEEiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwidHlwZSI6ImFjY2VzcyIsInVzZXJfaWQiOiJWWE5sY2pveU1RPT0iLCJpc19zdGFmZiI6dHJ1ZX0.jv57hd44KxRNMKO6IcP5bD7Upg2rnZ1fzXmsk0yAZDg\", \"user\": {\"id\": \"VXNlcjoyMQ==\", \"email\": \"admin@example.com\", \"firstName\": \"\", \"lastName\": \"\", \"userPermissions\": [{\"code\": \"MANAGE_APPS\", \"name\": \"Manage apps\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_CHECKOUTS\", \"name\": \"Manage checkouts\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_DISCOUNTS\", \"name\": \"Manage sales and vouchers.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_GIFT_CARD\", \"name\": \"Manage gift cards.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_MENUS\", \"name\": \"Manage navigation.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_ORDERS\", \"name\": \"Manage orders.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PAGES\", \"name\": \"Manage pages.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PLUGINS\", \"name\": \"Manage plugins\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PRODUCTS\", \"name\": \"Manage products.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_SETTINGS\", \"name\": \"Manage settings.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_SHIPPING\", \"name\": \"Manage shipping.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_STAFF\", \"name\": \"Manage staff.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_TRANSLATIONS\", \"name\": \"Manage translations.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_USERS\", \"name\": \"Manage customers.\", \"__typename\": \"UserPermission\"}], \"avatar\": null, \"__typename\": \"User\"}, \"__typename\": \"CreateToken\"}}}]"
|
||||||
},
|
},
|
||||||
"cookies": [
|
"cookies": [
|
||||||
{
|
{
|
||||||
"expires": "2020-08-20T13:55:42.000Z",
|
"expires": "2020-07-22T09:49:45.000Z",
|
||||||
"httpOnly": true,
|
"httpOnly": true,
|
||||||
"maxAge": 2592000,
|
"maxAge": 1800,
|
||||||
"name": "refreshToken",
|
"name": "refreshToken",
|
||||||
"path": "/",
|
"path": "/",
|
||||||
"secure": true,
|
"secure": true,
|
||||||
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTUzMzk3NDIsImV4cCI6MTU5NzkzMTc0MiwidG9rZW4iOiJxQ1Jia0dOMnpOT28iLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwidHlwZSI6InJlZnJlc2giLCJ1c2VyX2lkIjoiVlhObGNqb3lNUT09IiwiaXNfc3RhZmYiOnRydWUsImNzcmZUb2tlbiI6ImZiRzlQR3FtR2dLZnRlTEJZNHIycW9kV0J0djczeDF6SEtnM3JVRXQweXdZT081bVk0dGRFcE9DRVYxVGpUREoifQ.OmbZJ6T-gseVTakIUNv2IP0rZ_t-W6TmV3Z99jiPF64"
|
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTU0MDk1ODUsImV4cCI6MTU5NTQxMTM4NSwidG9rZW4iOiJDM1NrMmtMUlZ1UEEiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwidHlwZSI6InJlZnJlc2giLCJ1c2VyX2lkIjoiVlhObGNqb3lNUT09IiwiaXNfc3RhZmYiOnRydWUsImNzcmZUb2tlbiI6Im9RM3lIUnJCUlJ0UU5WdUpnbjRENlR4aDNhUFdDOGZsOTFYTWNBMmJ1a2Jna2RVb3RBRUFKYkFjQ3ZUc1huM1oifQ.KeIbqoHp-XPFfny6tlq6EUA7BojWAnNcpePMtI2X4qo"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"headers": [
|
"headers": [
|
||||||
{
|
{
|
||||||
"name": "date",
|
"name": "date",
|
||||||
"value": "Tue, 21 Jul 2020 13:55:42 GMT"
|
"value": "Wed, 22 Jul 2020 09:19:45 GMT"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "server",
|
"name": "server",
|
||||||
|
@ -106,7 +106,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "content-length",
|
"name": "content-length",
|
||||||
"value": "1749"
|
"value": "1830"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "x-content-type-options",
|
"name": "x-content-type-options",
|
||||||
|
@ -115,17 +115,17 @@
|
||||||
{
|
{
|
||||||
"_fromType": "array",
|
"_fromType": "array",
|
||||||
"name": "set-cookie",
|
"name": "set-cookie",
|
||||||
"value": "refreshToken=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTUzMzk3NDIsImV4cCI6MTU5NzkzMTc0MiwidG9rZW4iOiJxQ1Jia0dOMnpOT28iLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwidHlwZSI6InJlZnJlc2giLCJ1c2VyX2lkIjoiVlhObGNqb3lNUT09IiwiaXNfc3RhZmYiOnRydWUsImNzcmZUb2tlbiI6ImZiRzlQR3FtR2dLZnRlTEJZNHIycW9kV0J0djczeDF6SEtnM3JVRXQweXdZT081bVk0dGRFcE9DRVYxVGpUREoifQ.OmbZJ6T-gseVTakIUNv2IP0rZ_t-W6TmV3Z99jiPF64; expires=Thu, 20 Aug 2020 13:55:42 GMT; HttpOnly; Max-Age=2592000; Path=/; Secure"
|
"value": "refreshToken=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTU0MDk1ODUsImV4cCI6MTU5NTQxMTM4NSwidG9rZW4iOiJDM1NrMmtMUlZ1UEEiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwidHlwZSI6InJlZnJlc2giLCJ1c2VyX2lkIjoiVlhObGNqb3lNUT09IiwiaXNfc3RhZmYiOnRydWUsImNzcmZUb2tlbiI6Im9RM3lIUnJCUlJ0UU5WdUpnbjRENlR4aDNhUFdDOGZsOTFYTWNBMmJ1a2Jna2RVb3RBRUFKYkFjQ3ZUc1huM1oifQ.KeIbqoHp-XPFfny6tlq6EUA7BojWAnNcpePMtI2X4qo; expires=Wed, 22 Jul 2020 09:49:45 GMT; HttpOnly; Max-Age=1800; Path=/; Secure"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"headersSize": 804,
|
"headersSize": 801,
|
||||||
"httpVersion": "HTTP/1.1",
|
"httpVersion": "HTTP/1.1",
|
||||||
"redirectURL": "",
|
"redirectURL": "",
|
||||||
"status": 200,
|
"status": 200,
|
||||||
"statusText": "OK"
|
"statusText": "OK"
|
||||||
},
|
},
|
||||||
"startedDateTime": "2020-07-21T13:55:42.298Z",
|
"startedDateTime": "2020-07-22T09:19:45.127Z",
|
||||||
"time": 198,
|
"time": 324,
|
||||||
"timings": {
|
"timings": {
|
||||||
"blocked": -1,
|
"blocked": -1,
|
||||||
"connect": -1,
|
"connect": -1,
|
||||||
|
@ -133,7 +133,7 @@
|
||||||
"receive": 0,
|
"receive": 0,
|
||||||
"send": 0,
|
"send": 0,
|
||||||
"ssl": -1,
|
"ssl": -1,
|
||||||
"wait": 198
|
"wait": 324
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
},
|
},
|
||||||
"entries": [
|
"entries": [
|
||||||
{
|
{
|
||||||
"_id": "482243508a181587879cd204a88524d7",
|
"_id": "29fb7ad4777c005f81fdfd957c1c81af",
|
||||||
"_order": 0,
|
"_order": 0,
|
||||||
"cache": {},
|
"cache": {},
|
||||||
"request": {
|
"request": {
|
||||||
"bodySize": 1263,
|
"bodySize": 588,
|
||||||
"cookies": [],
|
"cookies": [],
|
||||||
"headers": [
|
"headers": [
|
||||||
{
|
{
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
{
|
{
|
||||||
"_fromType": "array",
|
"_fromType": "array",
|
||||||
"name": "content-length",
|
"name": "content-length",
|
||||||
"value": "1263"
|
"value": "588"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"_fromType": "array",
|
"_fromType": "array",
|
||||||
|
@ -50,29 +50,29 @@
|
||||||
"value": "localhost:8000"
|
"value": "localhost:8000"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"headersSize": 255,
|
"headersSize": 254,
|
||||||
"httpVersion": "HTTP/1.1",
|
"httpVersion": "HTTP/1.1",
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"postData": {
|
"postData": {
|
||||||
"mimeType": "application/json",
|
"mimeType": "application/json",
|
||||||
"params": [],
|
"params": [],
|
||||||
"text": "[{\"operationName\":\"VerifyToken\",\"variables\":{\"token\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTUzMzk3NDIsImV4cCI6MTU5NTM0MDA0MiwidG9rZW4iOiJxQ1Jia0dOMnpOT28iLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwidHlwZSI6ImFjY2VzcyIsInVzZXJfaWQiOiJWWE5sY2pveU1RPT0iLCJpc19zdGFmZiI6dHJ1ZX0.hZ2hTVOU8h7fMf--Qm891DpV1hssicEaQShyy4sPKXM\"},\"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\"},{\"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 token\\n errors: accountErrors {\\n field\\n message\\n __typename\\n }\\n user {\\n ...User\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}]"
|
"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\"}]"
|
||||||
},
|
},
|
||||||
"queryString": [],
|
"queryString": [],
|
||||||
"url": "http://localhost:8000/graphql/"
|
"url": "http://localhost:8000/graphql/"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"bodySize": 1814,
|
"bodySize": 214,
|
||||||
"content": {
|
"content": {
|
||||||
"mimeType": "application/json",
|
"mimeType": "application/json",
|
||||||
"size": 1814,
|
"size": 214,
|
||||||
"text": "[{\"data\": {\"tokenVerify\": {\"payload\": {\"iat\": 1595339742, \"exp\": 1595340042, \"token\": \"qCRbkGN2zNOo\", \"email\": \"admin@example.com\", \"type\": \"access\", \"user_id\": \"VXNlcjoyMQ==\", \"is_staff\": true}, \"user\": {\"id\": \"VXNlcjoyMQ==\", \"email\": \"admin@example.com\", \"firstName\": \"\", \"lastName\": \"\", \"userPermissions\": [{\"code\": \"MANAGE_APPS\", \"name\": \"Manage apps\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_CHECKOUTS\", \"name\": \"Manage checkouts\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_DISCOUNTS\", \"name\": \"Manage sales and vouchers.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_GIFT_CARD\", \"name\": \"Manage gift cards.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_MENUS\", \"name\": \"Manage navigation.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_ORDERS\", \"name\": \"Manage orders.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PAGES\", \"name\": \"Manage pages.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PLUGINS\", \"name\": \"Manage plugins\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PRODUCTS\", \"name\": \"Manage products.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_SETTINGS\", \"name\": \"Manage settings.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_SHIPPING\", \"name\": \"Manage shipping.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_STAFF\", \"name\": \"Manage staff.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_TRANSLATIONS\", \"name\": \"Manage translations.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_USERS\", \"name\": \"Manage customers.\", \"__typename\": \"UserPermission\"}], \"avatar\": null, \"__typename\": \"User\"}, \"__typename\": \"VerifyToken\"}}}, {\"data\": {\"tokenCreate\": {\"token\": null, \"errors\": [{\"field\": \"email\", \"message\": \"Please, enter valid credentials\", \"__typename\": \"AccountError\"}], \"user\": null, \"__typename\": \"CreateToken\"}}}]"
|
"text": "[{\"data\": {\"tokenCreate\": {\"errors\": [{\"field\": \"email\", \"message\": \"Please, enter valid credentials\", \"__typename\": \"AccountError\"}], \"csrfToken\": null, \"token\": null, \"user\": null, \"__typename\": \"CreateToken\"}}}]"
|
||||||
},
|
},
|
||||||
"cookies": [],
|
"cookies": [],
|
||||||
"headers": [
|
"headers": [
|
||||||
{
|
{
|
||||||
"name": "date",
|
"name": "date",
|
||||||
"value": "Tue, 21 Jul 2020 13:55:42 GMT"
|
"value": "Wed, 22 Jul 2020 09:21:11 GMT"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "server",
|
"name": "server",
|
||||||
|
@ -96,21 +96,21 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "content-length",
|
"name": "content-length",
|
||||||
"value": "1814"
|
"value": "214"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "x-content-type-options",
|
"name": "x-content-type-options",
|
||||||
"value": "nosniff"
|
"value": "nosniff"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"headersSize": 316,
|
"headersSize": 315,
|
||||||
"httpVersion": "HTTP/1.1",
|
"httpVersion": "HTTP/1.1",
|
||||||
"redirectURL": "",
|
"redirectURL": "",
|
||||||
"status": 200,
|
"status": 200,
|
||||||
"statusText": "OK"
|
"statusText": "OK"
|
||||||
},
|
},
|
||||||
"startedDateTime": "2020-07-21T13:55:42.541Z",
|
"startedDateTime": "2020-07-22T09:21:11.006Z",
|
||||||
"time": 185,
|
"time": 363,
|
||||||
"timings": {
|
"timings": {
|
||||||
"blocked": -1,
|
"blocked": -1,
|
||||||
"connect": -1,
|
"connect": -1,
|
||||||
|
@ -118,7 +118,7 @@
|
||||||
"receive": 0,
|
"receive": 0,
|
||||||
"send": 0,
|
"send": 0,
|
||||||
"ssl": -1,
|
"ssl": -1,
|
||||||
"wait": 185
|
"wait": 363
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -29,6 +29,7 @@ const credentials = {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
|
sessionStorage.clear();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("User", () => {
|
describe("User", () => {
|
||||||
|
|
|
@ -24,9 +24,10 @@ import { TokenAuth, TokenAuthVariables } from "./types/TokenAuth";
|
||||||
import { VerifyToken, VerifyTokenVariables } from "./types/VerifyToken";
|
import { VerifyToken, VerifyTokenVariables } from "./types/VerifyToken";
|
||||||
import {
|
import {
|
||||||
displayDemoMessage,
|
displayDemoMessage,
|
||||||
getAuthToken,
|
getTokens,
|
||||||
removeAuthToken,
|
removeTokens,
|
||||||
setAuthToken
|
setAuthToken,
|
||||||
|
setTokens
|
||||||
} from "./utils";
|
} from "./utils";
|
||||||
|
|
||||||
const persistToken = false;
|
const persistToken = false;
|
||||||
|
@ -38,13 +39,14 @@ export function useAuthProvider(
|
||||||
) {
|
) {
|
||||||
const [userContext, setUserContext] = useState<undefined | User>(undefined);
|
const [userContext, setUserContext] = useState<undefined | User>(undefined);
|
||||||
const autologinPromise = useRef<Promise<any>>();
|
const autologinPromise = useRef<Promise<any>>();
|
||||||
|
const refreshPromise = useRef<Promise<boolean>>();
|
||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
setUserContext(undefined);
|
setUserContext(undefined);
|
||||||
if (isCredentialsManagementAPISupported) {
|
if (isCredentialsManagementAPISupported) {
|
||||||
navigator.credentials.preventSilentAccess();
|
navigator.credentials.preventSilentAccess();
|
||||||
}
|
}
|
||||||
removeAuthToken();
|
removeTokens();
|
||||||
};
|
};
|
||||||
|
|
||||||
const [tokenAuth, tokenAuthResult] = useMutation<
|
const [tokenAuth, tokenAuthResult] = useMutation<
|
||||||
|
@ -63,7 +65,11 @@ export function useAuthProvider(
|
||||||
// `null`, because the LoginView uses this `null` to display error.
|
// `null`, because the LoginView uses this `null` to display error.
|
||||||
setUserContext(user);
|
setUserContext(user);
|
||||||
if (user) {
|
if (user) {
|
||||||
setAuthToken(result.tokenCreate.token, persistToken);
|
setTokens(
|
||||||
|
result.tokenCreate.token,
|
||||||
|
result.tokenCreate.csrfToken,
|
||||||
|
persistToken
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: logout
|
onError: logout
|
||||||
|
@ -110,7 +116,7 @@ export function useAuthProvider(
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const token = getAuthToken();
|
const token = getTokens().auth;
|
||||||
if (!!token && !userContext) {
|
if (!!token && !userContext) {
|
||||||
autologinPromise.current = tokenVerify({ variables: { token } });
|
autologinPromise.current = tokenVerify({ variables: { token } });
|
||||||
} else {
|
} else {
|
||||||
|
@ -133,17 +139,28 @@ export function useAuthProvider(
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const loginByToken = (token: string, user: User) => {
|
const loginByToken = (auth: string, refresh: string, user: User) => {
|
||||||
setUserContext(user);
|
setUserContext(user);
|
||||||
setAuthToken(token, persistToken);
|
setTokens(auth, refresh, persistToken);
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshToken = async () => {
|
const refreshToken = (): Promise<boolean> => {
|
||||||
const token = getAuthToken();
|
if (!!refreshPromise.current) {
|
||||||
|
return refreshPromise.current;
|
||||||
|
}
|
||||||
|
|
||||||
const refreshData = await tokenRefresh({ variables: { token } });
|
return new Promise(resolve => {
|
||||||
|
const token = getTokens().refresh;
|
||||||
|
|
||||||
setAuthToken(refreshData.data.tokenRefresh.token, persistToken);
|
return tokenRefresh({ variables: { token } }).then(refreshData => {
|
||||||
|
if (!!refreshData.data.tokenRefresh?.token) {
|
||||||
|
setAuthToken(refreshData.data.tokenRefresh.token, persistToken);
|
||||||
|
return resolve(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolve(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -199,7 +216,7 @@ export const useAuth = () => {
|
||||||
const isAuthenticated = !!user.user;
|
const isAuthenticated = !!user.user;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hasToken: !!getAuthToken(),
|
hasToken: !!getTokens(),
|
||||||
isAuthenticated,
|
isAuthenticated,
|
||||||
tokenAuthLoading: user.tokenAuthLoading,
|
tokenAuthLoading: user.tokenAuthLoading,
|
||||||
tokenVerifyLoading: user.tokenVerifyLoading,
|
tokenVerifyLoading: user.tokenVerifyLoading,
|
||||||
|
|
|
@ -11,6 +11,10 @@ export function isJwtError(error: GraphQLError): boolean {
|
||||||
return !!findValueInEnum(error.extensions.exception.code, JWTError);
|
return !!findValueInEnum(error.extensions.exception.code, JWTError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isJwtExpiredError(error: GraphQLError): boolean {
|
||||||
|
return error.extensions.exception.code === JWTError.expired;
|
||||||
|
}
|
||||||
|
|
||||||
export function isTokenExpired(error: GraphQLError): boolean {
|
export function isTokenExpired(error: GraphQLError): boolean {
|
||||||
return error.extensions.exception.code === JWTError.expired;
|
return error.extensions.exception.code === JWTError.expired;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,10 @@ import ResetPasswordSuccess from "./views/ResetPasswordSuccess";
|
||||||
|
|
||||||
interface UserContext {
|
interface UserContext {
|
||||||
login: (username: string, password: string) => void;
|
login: (username: string, password: string) => void;
|
||||||
loginByToken: (token: string, user: User) => void;
|
loginByToken: (auth: string, csrf: string, user: User) => void;
|
||||||
logout: () => void;
|
logout: () => void;
|
||||||
tokenAuthLoading: boolean;
|
tokenAuthLoading: boolean;
|
||||||
tokenRefresh: () => Promise<void>;
|
tokenRefresh: () => Promise<boolean>;
|
||||||
tokenVerifyLoading: boolean;
|
tokenVerifyLoading: boolean;
|
||||||
user?: User;
|
user?: User;
|
||||||
}
|
}
|
||||||
|
|
39
src/auth/link.ts
Normal file
39
src/auth/link.ts
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import { setContext } from "apollo-link-context";
|
||||||
|
import { ErrorResponse, onError } from "apollo-link-error";
|
||||||
|
|
||||||
|
import { getTokens, removeTokens } from "./";
|
||||||
|
import { isJwtError, JWTError } from "./errors";
|
||||||
|
|
||||||
|
interface ResponseError extends ErrorResponse {
|
||||||
|
networkError?: Error & {
|
||||||
|
statusCode?: number;
|
||||||
|
bodyText?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const invalidTokenLink = onError((error: ResponseError) => {
|
||||||
|
if (
|
||||||
|
(error.networkError && error.networkError.statusCode === 401) ||
|
||||||
|
error.graphQLErrors?.some(isJwtError)
|
||||||
|
) {
|
||||||
|
if (error.graphQLErrors[0].extensions.code !== JWTError.expired) {
|
||||||
|
removeTokens();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const tokenLink = setContext((_, context) => {
|
||||||
|
const authToken = getTokens().auth;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...context,
|
||||||
|
headers: {
|
||||||
|
...context.headers,
|
||||||
|
Authorization: authToken ? `JWT ${authToken}` : null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const link = invalidTokenLink.concat(tokenLink);
|
||||||
|
|
||||||
|
export default link;
|
|
@ -13,11 +13,12 @@ export const tokenAuthMutation = gql`
|
||||||
${fragmentUser}
|
${fragmentUser}
|
||||||
mutation TokenAuth($email: String!, $password: String!) {
|
mutation TokenAuth($email: String!, $password: String!) {
|
||||||
tokenCreate(email: $email, password: $password) {
|
tokenCreate(email: $email, password: $password) {
|
||||||
token
|
|
||||||
errors: accountErrors {
|
errors: accountErrors {
|
||||||
field
|
field
|
||||||
message
|
message
|
||||||
}
|
}
|
||||||
|
csrfToken
|
||||||
|
token
|
||||||
user {
|
user {
|
||||||
...User
|
...User
|
||||||
}
|
}
|
||||||
|
@ -68,6 +69,8 @@ export const setPassword = gql`
|
||||||
errors: accountErrors {
|
errors: accountErrors {
|
||||||
...AccountErrorFragment
|
...AccountErrorFragment
|
||||||
}
|
}
|
||||||
|
csrfToken
|
||||||
|
refreshToken
|
||||||
token
|
token
|
||||||
user {
|
user {
|
||||||
...User
|
...User
|
||||||
|
|
|
@ -38,6 +38,8 @@ export interface SetPassword_setPassword_user {
|
||||||
export interface SetPassword_setPassword {
|
export interface SetPassword_setPassword {
|
||||||
__typename: "SetPassword";
|
__typename: "SetPassword";
|
||||||
errors: SetPassword_setPassword_errors[];
|
errors: SetPassword_setPassword_errors[];
|
||||||
|
csrfToken: string | null;
|
||||||
|
refreshToken: string | null;
|
||||||
token: string | null;
|
token: string | null;
|
||||||
user: SetPassword_setPassword_user | null;
|
user: SetPassword_setPassword_user | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,8 +37,9 @@ export interface TokenAuth_tokenCreate_user {
|
||||||
|
|
||||||
export interface TokenAuth_tokenCreate {
|
export interface TokenAuth_tokenCreate {
|
||||||
__typename: "CreateToken";
|
__typename: "CreateToken";
|
||||||
token: string | null;
|
|
||||||
errors: TokenAuth_tokenCreate_errors[];
|
errors: TokenAuth_tokenCreate_errors[];
|
||||||
|
csrfToken: string | null;
|
||||||
|
token: string | null;
|
||||||
user: TokenAuth_tokenCreate_user | null;
|
user: TokenAuth_tokenCreate_user | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,20 +2,43 @@ import { UseNotifierResult } from "@saleor/hooks/useNotifier";
|
||||||
import { commonMessages } from "@saleor/intl";
|
import { commonMessages } from "@saleor/intl";
|
||||||
import { IntlShape } from "react-intl";
|
import { IntlShape } from "react-intl";
|
||||||
|
|
||||||
const TOKEN_STORAGE_KEY = "dashboardAuth";
|
export enum TOKEN_STORAGE_KEY {
|
||||||
|
AUTH = "auth",
|
||||||
|
CSRF = "csrf"
|
||||||
|
}
|
||||||
|
|
||||||
export const getAuthToken = () =>
|
export const getTokens = () => ({
|
||||||
localStorage.getItem(TOKEN_STORAGE_KEY) ||
|
auth:
|
||||||
sessionStorage.getItem(TOKEN_STORAGE_KEY);
|
localStorage.getItem(TOKEN_STORAGE_KEY.AUTH) ||
|
||||||
|
sessionStorage.getItem(TOKEN_STORAGE_KEY.AUTH),
|
||||||
|
refresh:
|
||||||
|
localStorage.getItem(TOKEN_STORAGE_KEY.CSRF) ||
|
||||||
|
sessionStorage.getItem(TOKEN_STORAGE_KEY.CSRF)
|
||||||
|
});
|
||||||
|
|
||||||
export const setAuthToken = (token: string, persist: boolean) =>
|
export const setTokens = (auth: string, csrf: string, persist: boolean) => {
|
||||||
persist
|
if (persist) {
|
||||||
? localStorage.setItem(TOKEN_STORAGE_KEY, token)
|
localStorage.setItem(TOKEN_STORAGE_KEY.AUTH, auth);
|
||||||
: sessionStorage.setItem(TOKEN_STORAGE_KEY, token);
|
localStorage.setItem(TOKEN_STORAGE_KEY.CSRF, csrf);
|
||||||
|
} else {
|
||||||
|
sessionStorage.setItem(TOKEN_STORAGE_KEY.AUTH, auth);
|
||||||
|
sessionStorage.setItem(TOKEN_STORAGE_KEY.CSRF, csrf);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const removeAuthToken = () => {
|
export const setAuthToken = (auth: string, persist: boolean) => {
|
||||||
localStorage.removeItem(TOKEN_STORAGE_KEY);
|
if (persist) {
|
||||||
sessionStorage.removeItem(TOKEN_STORAGE_KEY);
|
localStorage.setItem(TOKEN_STORAGE_KEY.AUTH, auth);
|
||||||
|
} else {
|
||||||
|
sessionStorage.setItem(TOKEN_STORAGE_KEY.AUTH, auth);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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 = (
|
export const displayDemoMessage = (
|
||||||
|
|
|
@ -19,7 +19,11 @@ const NewPassword: React.FC<RouteComponentProps> = ({ location }) => {
|
||||||
|
|
||||||
const handleSetPassword = async (data: SetPassword) => {
|
const handleSetPassword = async (data: SetPassword) => {
|
||||||
if (data.setPassword.errors.length === 0) {
|
if (data.setPassword.errors.length === 0) {
|
||||||
loginByToken(data.setPassword.token, data.setPassword.user);
|
loginByToken(
|
||||||
|
data.setPassword.token,
|
||||||
|
data.setPassword.csrfToken,
|
||||||
|
data.setPassword.user
|
||||||
|
);
|
||||||
navigate("/", true);
|
navigate("/", true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { isJwtError } from "@saleor/auth/errors";
|
import { isJwtError, isJwtExpiredError } from "@saleor/auth/errors";
|
||||||
import { commonMessages } from "@saleor/intl";
|
import { commonMessages } from "@saleor/intl";
|
||||||
import { maybe, RequireAtLeastOne } from "@saleor/misc";
|
import { maybe, RequireAtLeastOne } from "@saleor/misc";
|
||||||
import { ApolloQueryResult } from "apollo-client";
|
import { ApolloError, ApolloQueryResult } from "apollo-client";
|
||||||
import { DocumentNode } from "graphql";
|
import { DocumentNode } from "graphql";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { QueryResult, useQuery as useBaseQuery } from "react-apollo";
|
import { QueryResult, useQuery as useBaseQuery } from "react-apollo";
|
||||||
|
@ -48,6 +48,37 @@ function makeQuery<TData, TVariables>(
|
||||||
},
|
},
|
||||||
errorPolicy: "all",
|
errorPolicy: "all",
|
||||||
fetchPolicy: "cache-and-network",
|
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)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
skip,
|
skip,
|
||||||
variables
|
variables
|
||||||
});
|
});
|
||||||
|
@ -63,26 +94,6 @@ function makeQuery<TData, TVariables>(
|
||||||
}
|
}
|
||||||
}, [queryData.loading]);
|
}, [queryData.loading]);
|
||||||
|
|
||||||
if (queryData.error) {
|
|
||||||
if (queryData.error.graphQLErrors.some(isJwtError)) {
|
|
||||||
user.logout();
|
|
||||||
notify({
|
|
||||||
status: "error",
|
|
||||||
text: intl.formatMessage(commonMessages.sessionExpired)
|
|
||||||
});
|
|
||||||
} else if (
|
|
||||||
!queryData.error.graphQLErrors.every(
|
|
||||||
err =>
|
|
||||||
maybe(() => err.extensions.exception.code) === "PermissionDenied"
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
notify({
|
|
||||||
status: "error",
|
|
||||||
text: intl.formatMessage(commonMessages.somethingWentWrong)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadMore = (
|
const loadMore = (
|
||||||
mergeFunc: (previousResults: TData, fetchMoreResult: TData) => TData,
|
mergeFunc: (previousResults: TData, fetchMoreResult: TData) => TData,
|
||||||
extraVariables: RequireAtLeastOne<TVariables>
|
extraVariables: RequireAtLeastOne<TVariables>
|
||||||
|
|
|
@ -4,8 +4,6 @@ import { defaultDataIdFromObject, InMemoryCache } from "apollo-cache-inmemory";
|
||||||
import { ApolloClient } from "apollo-client";
|
import { ApolloClient } from "apollo-client";
|
||||||
import { ApolloLink } from "apollo-link";
|
import { ApolloLink } from "apollo-link";
|
||||||
import { BatchHttpLink } from "apollo-link-batch-http";
|
import { BatchHttpLink } from "apollo-link-batch-http";
|
||||||
import { setContext } from "apollo-link-context";
|
|
||||||
import { ErrorResponse, onError } from "apollo-link-error";
|
|
||||||
import { createUploadLink } from "apollo-upload-client";
|
import { createUploadLink } from "apollo-upload-client";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { ApolloProvider } from "react-apollo";
|
import { ApolloProvider } from "react-apollo";
|
||||||
|
@ -19,11 +17,11 @@ import AppsSection from "./apps";
|
||||||
import { appsSection } from "./apps/urls";
|
import { appsSection } from "./apps/urls";
|
||||||
import AttributeSection from "./attributes";
|
import AttributeSection from "./attributes";
|
||||||
import { attributeSection } from "./attributes/urls";
|
import { attributeSection } from "./attributes/urls";
|
||||||
import Auth, { getAuthToken, removeAuthToken } from "./auth";
|
import Auth from "./auth";
|
||||||
import AuthProvider, { useAuth } from "./auth/AuthProvider";
|
import AuthProvider, { useAuth } from "./auth/AuthProvider";
|
||||||
import LoginLoading from "./auth/components/LoginLoading/LoginLoading";
|
import LoginLoading from "./auth/components/LoginLoading/LoginLoading";
|
||||||
import SectionRoute from "./auth/components/SectionRoute";
|
import SectionRoute from "./auth/components/SectionRoute";
|
||||||
import { isJwtError } from "./auth/errors";
|
import authLink from "./auth/link";
|
||||||
import { hasPermission } from "./auth/misc";
|
import { hasPermission } from "./auth/misc";
|
||||||
import CategorySection from "./categories";
|
import CategorySection from "./categories";
|
||||||
import CollectionSection from "./collections";
|
import CollectionSection from "./collections";
|
||||||
|
@ -60,43 +58,15 @@ import { PermissionEnum } from "./types/globalTypes";
|
||||||
import WarehouseSection from "./warehouses";
|
import WarehouseSection from "./warehouses";
|
||||||
import { warehouseSection } from "./warehouses/urls";
|
import { warehouseSection } from "./warehouses/urls";
|
||||||
|
|
||||||
interface ResponseError extends ErrorResponse {
|
|
||||||
networkError?: Error & {
|
|
||||||
statusCode?: number;
|
|
||||||
bodyText?: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.env.GTM_ID !== undefined) {
|
if (process.env.GTM_ID !== undefined) {
|
||||||
TagManager.initialize({ gtmId: GTM_ID });
|
TagManager.initialize({ gtmId: GTM_ID });
|
||||||
}
|
}
|
||||||
|
|
||||||
const invalidTokenLink = onError((error: ResponseError) => {
|
|
||||||
if (
|
|
||||||
(error.networkError && error.networkError.statusCode === 401) ||
|
|
||||||
error.graphQLErrors?.some(isJwtError)
|
|
||||||
) {
|
|
||||||
removeAuthToken();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const authLink = setContext((_, context) => {
|
|
||||||
const authToken = getAuthToken();
|
|
||||||
|
|
||||||
return {
|
|
||||||
...context,
|
|
||||||
headers: {
|
|
||||||
...context.headers,
|
|
||||||
Authorization: authToken ? `JWT ${authToken}` : null
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// DON'T TOUCH THIS
|
// DON'T TOUCH THIS
|
||||||
// These are separate clients and do not share configs between themselves
|
// These are separate clients and do not share configs between themselves
|
||||||
// so we need to explicitly set them
|
// so we need to explicitly set them
|
||||||
const linkOptions = {
|
const linkOptions = {
|
||||||
credentials: "same-origin",
|
credentials: "include",
|
||||||
uri: API_URI
|
uri: API_URI
|
||||||
};
|
};
|
||||||
const uploadLink = createUploadLink(linkOptions);
|
const uploadLink = createUploadLink(linkOptions);
|
||||||
|
@ -122,7 +92,7 @@ const apolloClient = new ApolloClient({
|
||||||
return defaultDataIdFromObject(obj);
|
return defaultDataIdFromObject(obj);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
link: invalidTokenLink.concat(authLink.concat(link))
|
link: authLink.concat(link)
|
||||||
});
|
});
|
||||||
|
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { ApolloQueryResult } from "apollo-client";
|
import { ApolloError, ApolloQueryResult } from "apollo-client";
|
||||||
import { DocumentNode } from "graphql";
|
import { DocumentNode } from "graphql";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Query, QueryResult } from "react-apollo";
|
import { Query, QueryResult } from "react-apollo";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
import { isJwtError } from "./auth/errors";
|
import { isJwtError, isJwtExpiredError } from "./auth/errors";
|
||||||
import useAppState from "./hooks/useAppState";
|
import useAppState from "./hooks/useAppState";
|
||||||
import useNotifier from "./hooks/useNotifier";
|
import useNotifier from "./hooks/useNotifier";
|
||||||
import useUser from "./hooks/useUser";
|
import useUser from "./hooks/useUser";
|
||||||
|
@ -79,29 +79,40 @@ export function TypedQuery<TData, TVariables>(
|
||||||
skip={skip}
|
skip={skip}
|
||||||
context={{ useBatching: true }}
|
context={{ useBatching: true }}
|
||||||
errorPolicy="all"
|
errorPolicy="all"
|
||||||
>
|
onError={async (error: ApolloError) => {
|
||||||
{(queryData: QueryResult<TData, TVariables>) => {
|
if (error.graphQLErrors.some(isJwtError)) {
|
||||||
if (queryData.error) {
|
if (error.graphQLErrors.every(isJwtExpiredError)) {
|
||||||
if (queryData.error.graphQLErrors.some(isJwtError)) {
|
const success = await user.tokenRefresh();
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
user.logout();
|
||||||
|
notify({
|
||||||
|
status: "error",
|
||||||
|
text: intl.formatMessage(commonMessages.sessionExpired)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
user.logout();
|
user.logout();
|
||||||
notify({
|
|
||||||
status: "error",
|
|
||||||
text: intl.formatMessage(commonMessages.sessionExpired)
|
|
||||||
});
|
|
||||||
} else if (
|
|
||||||
!queryData.error.graphQLErrors.every(
|
|
||||||
err =>
|
|
||||||
maybe(() => err.extensions.exception.code) ===
|
|
||||||
"PermissionDenied"
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
notify({
|
notify({
|
||||||
status: "error",
|
status: "error",
|
||||||
text: intl.formatMessage(commonMessages.somethingWentWrong)
|
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)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{(queryData: QueryResult<TData, TVariables>) => {
|
||||||
const loadMore = (
|
const loadMore = (
|
||||||
mergeFunc: (
|
mergeFunc: (
|
||||||
previousResults: TData,
|
previousResults: TData,
|
||||||
|
|
Loading…
Reference in a new issue