react-admin authentication flow not working - jwt

Working on authentication react-admin using JWT token and storing in memory as closure variable.
Creating AuthToken from Django works fine, it's emitting the Token with user info as JSON.
Here is inMemoryJWT Manager
File: inMemoryJwt.js
// https://github.com/marmelab/ra-in-memory-jwt
const inMemoryJWTManager = () => {
let inMemoryJWT = null;
let isRefreshing = null;
// Token code goes here
const getToken = () => inMemoryJWT;
const setToken = (token) => {
inMemoryJWT = token;
return true;
};
const ereaseToken = () => {
inMemoryJWT = null;
return true;
}
return {
ereaseToken,
getToken,
setToken,
}
};
export default inMemoryJWTManager();
File: AuthProvider.js
oryJWTManager';
const authProvider = {
login: ({ username, password }) => {
const request = new Request('http://127.0.0.1:8000/api/token-auth/', {
method: 'POST',
body: JSON.stringify({ username, password }),
headers: new Headers({ 'Content-Type': 'application/json' }),
});
return fetch(request)
.then(response => {
console.log('Response status ' + response.status )
if (response.status < 200 || response.status >= 300) {
throw new Error(response.statusText);
}
console.log('response.json is ');
console.log(response.json());
return response.json();
})
.then(({ token }) => {
console.log(' about to set token in storage .......... ');
JwtManager.setToken(token);
const decodedToken = decodeJwt(token);
# Its not setting in localstorage
localStorage.setItem('token', token);
console.log('Token from lS : -------------',localStorage.getIdentity('token'));
localStorage.setItem('permissions', decodedToken.permissions);
})
.then(auth => {
localStorage.setItem('auth', JSON.stringify(auth));
})
.catch(response => {
console.log('Catch : ' );
console.log(response.json());
throw new Error('Network errorkkkkkkkkkkkkk')
});
},
logout: () => {
localStorage.setItem('not_authenticated', true);
localStorage.removeItem('auth');
localStorage.removeItem('role');
localStorage.removeItem('login');
localStorage.removeItem('user');
localStorage.removeItem('avatar');
inMemoryJWT.ereaseToken();
return Promise.resolve();
},
checkError: ({ status }) => {
if (status === 401 || status === 403) {
inMemoryJWT.ereaseToken();
return Promise.reject();
}
return Promise.resolve();
// return status === 401 || status === 403
// ? Promise.reject( { redirectTo: '/login' , logoutUser: false} )
// : Promise.resolve();
},
checkAuth: () => {
return inMemoryJWT.getToken() ? Promise.resolve() : Promise.reject({ redirectTo: '/no-access', message: 'login.required' });
// localStorage.getItem('auth')
// ? Promise.resolve()
// : Promise.reject({ redirectTo: '/no-access', message: 'login.required' }),
},
getPermissions: () => {
return inMemoryJWT.getToken() ? Promise.resolve() : Promise.reject();
// const role = localStorage.getItem('permissions');
// return role ? Promise.resolve(role) : Promise.reject();
},
getIdentity: () => {
try {
const { id, fullName, avatar } = JSON.parse(localStorage.getItem('auth'));
return Promise.resolve({ id, fullName, avatar });
} catch (error) {
return Promise.reject(error);
}
// return {
// id: localStorage.getItem('login'),
// fullName: localStorage.getItem('user'),
// avatar: localStorage.getItem('avatar'),
// };
},
}
export default authProvider;
App.js
const httpClient = (url, options = {}) => {
if (!options.headers) {
options.headers = new Headers({ Accept: 'application/json' });
}
const { token } = JSON.parse(localStorage.getItem('auth'));
options.headers.set('Authorization', `Bearer ${token}`);
return fetchUtils.fetchJson(url, options);
};
const dataProvider = drfProvider('http://127.0.0.1:8000/api/token-auth/', httpClient);
const App = () => (
<Admin title=""
loginPage={Login}
catchAll={NotFound}
logoutButton={PfsLogoutButton}
authProvider={authProvider}
dataProvider={dataProvider}
catchAll={NotFound}
dashboard={Dashboard} disableTelemetry>
The problem
The problem I am facing is to, It's not setting in-memory or local storage, also I get the message in the footer on the login button clicked. I am breaking my head with it for quite some time. Let me know if you need any other info.
Login required error for every page
HTTP Response goes here

Related

Error while Uploading Image to Mongodb using Gridfs and Graphql

Im trying to upload an image to mogodb using graphql and gridfs. When trying to do i'm facing a error :
" JSON Parse error: Unexpected identifier "This" "
I'm not sure what I've done wrong in the code.
Can anyone help me figure out where I've gone wrong in the implementation
This is the part for uploading Image
const selectProfilePic = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [2, 3],
quality: 1,
});
handleImagePicked(result);
};
const handleImagePicked = async (result: ImagePicker.ImagePickerResult) => {
try {
if (result.cancelled) {
alert("Upload cancelled");
return;
} else {
console.log("In HERE ::: 76");
const lastIndex = result.uri.lastIndexOf("/") + 1;
console.log(result);
const file = new ReactNativeFile({
uri: result.uri,
name: result.uri.substring(lastIndex),
type: "image/png",
});
setAvatar(result.uri);
console.log(file); // This result is getting printed.
await singleUpload({ // I think the Upload function is not getting called.
variables: {
file,
},
});
}
} catch (e) {
console.log(e);
alert("Upload failed");
}
};
Resolver Function
singleUpload: async (_, { file }, context) => {
const {db, user, hhhhhh, gfs} = context;
console.log(gfs);
const res = uploadFn({ file },gfs);
console.log(res);
Apollo.tsx File
const uploadLink = createUploadLink({
uri: CLIENT_HTTP_URI,
});
// splitLink is defined here
export const client = new ApolloClient({
link: ApolloLink.from([authLink, splitLink]),
cache: new InMemoryCache(),
});
Have created StorageEngine.js File with this code
const storage = new GridFsStorage({
url: DB_URI,
file: (req, file) => {
return new Promise((resolve, reject) => {
crypto.randomBytes(16, (err, buf) => {
if(err) { return reject(err); }
const fileName = buf.toString('hex') + path.extname(file.originalname);
const fileInfo = {
fileName,
bucketName: 'uploads'
};
resolve(fileInfo);
});
});
}
});
const upload = multer({storage});
const uploadFn = async ({file}, bucket) => {
console.log(file);
const { createReadStream, name, type, encoding } = await file;
const uploadStream = bucket.openUploadStream(name, {
contentType: type
});
// console.log(uploadStream);
return new Promise((resolve, reject) => {
createReadStream()
.pipe(uploadStream)
.on('error', reject)
.on('finish', () => {
console.log(uploadStream.id);
resolve(uploadStream.id);
});
});
}

UI Doesn't update after SWR data does NEXTJS

I have a simple project going on and it is smoothly working but I have failed to add a item delete button. My post request to add items is perfectly working but my delete items doesn't work. I chose to go with post instead of delete because of my api structure.
Repo: https://github.com/berkaydagdeviren/rl-revenue-calculator
const handleClick = async (e) => {
e.preventDefault();
console.log(totalCredit, 'total credit before')
setTotalCredit([...totalCredit, credit])
console.log(ref, 'refFFFFFFF')
const currentDate = ref.current
const options = {
method: "PUT",
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify(
{ date: currentDate, credits: credit }
)
}
var responseClone;
fetch(`api/hello?date=${ref.current}`, options)
.then(res => {
responseClone = res.clone();
return res.json()
}).then(data => {
console.log(data, 'data')
}).then(function (data) {
// Do something with data
}, function (rejectionReason) { // 3
console.log('Error parsing JSON from response:', rejectionReason, responseClone); // 4
responseClone.text() // 5
.then(function (bodyText) {
console.log('Received the following instead of valid JSON:', bodyText); // 6
});
});
setCredit(0)
}
This is working perfectly fine but this does not;
const handleItemDelete = async itemToBeDeleted => {
console.log(itemToBeDeleted, "itemTobeDeleted")
const options = {
method: "PUT",
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify(
{ date: ref.current, index: itemToBeDeleted }
)
}
var responseClone;
await fetch(`api/hello?date=${ref.current}`, options)
.then(async res => {
responseClone = res.clone();
console.log(res, "res")
return await res.json()
// I used this to read server's response when it was giving parsing JSON error
}).then(data => {
console.log(data, 'data')
}).then(function (data) {
// Do something with data
}, function (rejectionReason) { // 3
console.log('Error parsing JSON from response:', rejectionReason, responseClone); // 4
responseClone.text() // 5
.then(function (bodyText) {
console.log('Received the following instead of valid JSON:', bodyText); // 6
});
});
const newTotalCredit = await data.find(item => item.date == ref.current).credits
setTotalCredit(newTotalCredit)
console.log("STATE UPDATED BEFORE DATA")
}
This is where I reference handleItemDelete to;
credit.map((item, index) => {
return (
item > 0 ?
React.Children.toArray(
<div>
<span style={{ color: 'green' }}> +{item}C </span>
<button onClick={() =>handleItemDelete(index)}>
X
</button>
</div>
)
:
null
)
})
}
And this is how I handle put request, again I can see that mongodb is updated after refresh but because ui didn't totalCredits' indexes are messed up and results in either no deletion or false deletion.
handler.put(async (req, res) => {
let data = req.body
console.log(typeof(data))
if (data.index) {
let {date, index} = req.body
console.log(data.index, "data.index")
await req.db.collection('credits').update({date: date}, {$unset: {["credits."+ index] : 1}})
await req.db.collection('credits').update({date: date}, {$pullAll: {credits: [null]}})
}
await req.db.collection('credits').updateOne({date: data.date}, {$push: {credits: data.credits}})
res.json(data)
})
I use SWR right in the index.js Home component
export default function Home()
{
const [totalCredit, setTotalCredit] = useState([])
const [credit, setCredit] = useState('')
const ref = useRef(null);
const [date, setDate] = useState(null);
const { data } = useSWR('/api/hello', async (url) => {const response = await axios.get(url);
return response.data; },
{ refreshInterval: 1000, revalidateOnMount: true });
Sorry if I'm not clear or providing wrong pieces of code please let me know. Thank you in advance!
your options in handleDeleteItem:
const options = {
method: "PUT",
headers: {
'Content-type': 'application/json'
},
Should not method be DELETE? You are sending PUT request instead of DELETE

Uncaught TypeError: Cannot read properties of undefined (reading 'type') with the redux-toolkit i'm facing this bug

I'm facing this error when I'm trying to a request my backend I'm using the redux toolkit for my project I read the documentation also but I can't understand why this is happening I'm a beginner in the redux toolkit so kindly assess me in this
here is my users like page
const signup = createAsyncThunk(
// you can there any thing its all your choice
'datauser/signup',
async (user, thunkAPI) => {
try {
const response = await userapi.signup(user)
console.log(response)
return response.data
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString()
return thunkAPI.rejectWithValue(message)
}
}
)
// initialize the state from there
const initialState = {
user: user?user:null,
isError: false,
isSuccess: false,
isLoading: false,
message: '',
}
export const registerslice = createSlice({
// name=.e.t.c is the type of the state
name: 'user',
initialState,
reducers: {
reset: (state) => {
state.isLoading = false
state.isSuccess = false
state.isError = false
state.message = ''
},
},
extraReducers: (builder) => {
builder
.addCase(signup.fulfilled, (state, action) => {
state.isLoading = false
state.isSuccess = true
state.user = action.payload
})
}
})
// Action creators are generated for each case reducer function
export const { reset } = registerslice.actions
export default registerslice.reducer
here is my apislice
const API = 'http://localhost:5000'
// register user
const signup= async(response,userData)=>{
const res=axios.post(`${API}/signup`,userData)
if (response.data) {
localStorage.setItem('user', JSON.stringify(response.data))
}
return res.data
}
this is my store
import userReducer from '../redux/userSlice'
export const store = configureStore({
reducer: {
auth: userReducer,
},
})

loging response from server does not work

I am following a tutorial from Coding Garden. There he writes to a database and sends it then back to the client.
When I try to do it, I do not get a respond from the server. I guess there has been a mix up in my code.
When I go to localhost/5000/posts there is no database. Why do I not get an errormessage, or a database?
Best regards
Expected Result:
https://youtu.be/JnEH9tYLxLk?t=3060
client code
const form = document.querySelector('form');
const loadingElement = document.querySelector(".loading");
const API_URL = "http://localhost:5000/posts";
loadingElement.style.display = "none";
form.addEventListener('submit', (event) => {
event.preventDefault();
const formData = new FormData(form);
const name = formData.get('name');
const content = formData.get('content');
const post = {
name,
content
};
form.style.display = "none";
loadingElement.style.display= "";
fetch(API_URL, {
method: "POST",
body: JSON.stringify(post),
headers: {
"content-type": "application/json"
}
}).then(response => response.json())
.then(createdPost => {
console.log(createdPost);
});
});
server code
const express = require("express");
const cors = require('cors');
const monk = require("monk");
const app = express();
const db = monk("localhost/posts");
const posts = db.get("posts");
app.use(cors());
app.use(express.json());
app.get("/", (req, res) => {
res.json({
message: "Post"
});
});
function isValidPost(post){
return post.name && post.name.toString().trim() !== "" &&
post.content && post.content.toString().trim() !=="";
}
app.post("/posts", (req, res) => {
if (isValidPost(req.body)){
const post = {
name: req.body.name.toString(),
content: req.body.content.toString(),
created: new Date()
};
//console.log(post);
posts
.insert(post)
.then(createdPost => {
res.json(createdPost);
});
}else {
res.status(422);
res.json({
message: "Hey, Titel und Inhalt werden benötigt!"
});
}
});
app.listen(5000, () => {
console.log('Listening on http://localhost:5000');
});
You forgot to handle the case when post.insert(...) fails and rejects. In this case no response is sent from your server and the request will hang. Add the following:
posts
.insert(post)
.then(createdPost => {
res.json(createdPost);
})
.catch(err => {
console.log(err);
res.status(500).json({errorMessage: err.message});
});
handle the fetch method with catch. It probably goes to catch.
fetch().then().catch(err => ...)

How can I do refresh auth token logiс with axios for multiple requests?

I was trying to do it like this, but for three requests it sends three refresh requests:
1, 2, 3 fails with 401
refresh success, 1 success, 2, 3 fails
refresh success, 2 success, 3 fails
refresh success 3 success
I can't put that much load on a mobile device (even if there was only 3 refresh without "refail")
Here is my code:
function requestRefreshToken(refreshToken, accessToken) {
return axios
.create({
baseURL: apiUrl + Endpoints.AUTH.REFRESH,
skipAuthRefresh: true,
headers: {
'Accept-Language': 'ru',
'User-Agent': `${Platform.OS} ${packageJson.version}`,
Authorization: accessToken,
},
})
.post(
'',
{
grant_type: GrantTypes.REFRESH_TOKEN,
refresh_token: refreshToken,
client_id: Client.id,
client_secret: Client.secret,
},
{ validateStatus },
);
}
const refreshAuthLogic = async failedRequest =>
Keychain.getCredentials()
.then(old => requestRefreshToken(old.refreshToken, old.accessToken))
.then(({ data: credentials }) => {
failedRequest.config.headers.Authorization = `${credentials.token_type} ${
credentials.access_token
}`;
return Keychain.setCredentials(credentials);
});
createAuthRefreshInterceptor(axios, refreshAuthLogic, {
retryInstance: axios,
skipWhileRefreshing: true,
onRetry: function(config) {
return Keychain.getCredentials().then(({ accessToken }) =>
axios({
...config,
header: { ...config.headers, Authorization: accessToken },
}),
);
},
});
axios.interceptors.response.use(
r => r,
request => {
if (request.response.status === 401) {
return Keychain.getCredentials().then(({ accessToken }) =>
axios({
...request.config,
header: { ...request.config.headers, Authorization: accessToken },
}),
);
}
},
);
Solved with this! Seems there is no way solving it without failed request queue( https://gist.github.com/mkjiau/650013a99c341c9f23ca00ccb213db1c
Here's a quick way I implemented it.
I found it a bit simpler to reason about the code.
I've adapted it from this solution:
HERE
let refreshTokenPromise: null | Promise < any > ;
instance.interceptors.response.use(r => {
const {
data
} = r;
if (data.errors && data.errors[0].message === "AUTH_EXPIRED") {
if (!refreshTokenPromise) {
refreshTokenPromise = fetchRefreshToken().then(data => {
refreshTokenPromise = null;
return data;
});
}
return refreshTokenPromise.then(token => {
if (r.config.headers) r.config.headers["Authorization"] = token;
return instance.request(r.config);
});
}
return r;
});