Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add defaultState option to remove a cookie for a specified default state #17

Closed
zhangwei900808 opened this issue Sep 8, 2021 · 13 comments
Labels
enhancement New feature or request released

Comments

@zhangwei900808
Copy link

when I login is success save cookie but how can I clear cookie when I logout?

@zhangwei900808
Copy link
Author

import Cookies from 'js-cookie'

// Create axios instance.
const axiosInstance = axios.create({
  baseURL: `${process.env.NEXT_PUBLIC_API_HOST}`,
  withCredentials: false,
});

axiosInstance.interceptors.response.use(response => {
  return response;
}, async error => {
  if (error.response.status === 401) {
    Cookies.remove('auth.me') // fail!
    Cookies.remove('auth.isLogin') // fail!
    Cookies.remove('auth.accessToken') // fail!
  }
  return error;
});

@zhangwei900808
Copy link
Author

who can help me?

@trangchongcheng
Copy link

me too, i need to remove the cookie if authentication fail

@bjoluc
Copy link
Owner

bjoluc commented Sep 12, 2021

Hi both,
I'm afraid deleting cookies is currently not supported (and if we deleted them directly on the client/server, they would be recreated again on the next state change / request), but I'd like to know your opinion on a feature idea I had:
What about having a per-subtree defaultState (or the like) option that, if provided, removes the cookie whenever a state subtree equals the provided default state?
When you log out, @zhangwei900808, you could set your state back to the default then and the cookie would disappear. Similarly, @trangchongcheng, you could reset the auth-related state when the authentication fails.

What do you think @zhangwei900808 @trangchongcheng?

@zhangwei900808
Copy link
Author

zhangwei900808 commented Sep 17, 2021

@bjoluc I know you said , but this a new problem , is when my token is expired axios status is 401 and axios file is not in reducer So I cant reset reducer when status = 401, do you have any methods to resolve it?
eg: axios.js

// Create axios instance.
const axiosInstance = axios.create({
  baseURL: `${process.env.NEXT_PUBLIC_API_HOST}`,
  withCredentials: false,
});

axiosInstance.interceptors.response.use(response => {
  return response;
}, async error => {
  if (error.response.status === 401) {
    //todo:how to call reducer reset initstate
  }
  return error;
});

@bjoluc
Copy link
Owner

bjoluc commented Sep 17, 2021

@zhangwei900808 I think you should be using redux-thunk to invoke axios in a context where you can dispatch Redux actions. next-redux-cookie-wrapper is designed to mirror Redux state changes to cookies and use them to share state between client and server, not to mirror cookie state changes to Redux (this only ever happens when the server updates cookies on page transitions). Hence you'll have to dispatch a Redux action when axios gets the response, and thunk actions are a good place to do so. You may find https://github.com/reduxjs/redux-thunk#why-do-i-need-this helpful.

@bjoluc bjoluc added the enhancement New feature or request label Sep 23, 2021
@zhangwei900808
Copy link
Author

zhangwei900808 commented Dec 8, 2021

@bjoluc I had resolve this problem and I read this article helped me React + Redux: Refresh Token with Axios and JWT example

store/index.js

import setupInterceptors from "./setupInterceptors";

const combinedReducers = combineReducers({
  [authSlice.name]: authSlice.reducer,
  [layoutSlice.name]: layoutSlice.reducer,
  [systemSlice.name]: systemSlice.reducer,
  [spaceSlice.name]: spaceSlice.reducer,
  [settingSlice.name]: settingSlice.reducer,
  [userSlice.name]: userSlice.reducer,
  [homeSlice.name]: homeSlice.reducer
});
export const store = wrapMakeStore(() => {
  const initStore = configureStore({
    reducer: combinedReducers,
    middleware: (getDefaultMiddleware) => getDefaultMiddleware().prepend(
      nextReduxCookieMiddleware({
        subtrees: ["auth.accessToken", "auth.refreshToken", "auth.isLogin", "auth.me"],
      })
    ).concat(logger)
  });
  setupInterceptors(initStore);
  return initStore;
});

const makeStore = () => store;

export const wrapper = createWrapper(store, {storeKey: 'key', debug: true});

axios.js

import axios from 'axios';

const axiosInstance = axios.create({
  baseURL: `${process.env.NEXT_PUBLIC_API_HOST}`,
  withCredentials: false,
});

export default axiosInstance;

setupInterceptors.js

import axiosInstance from "./axios";
import {logout, refresh} from '@/store/slices/authSlice'

const setup = (store) => {
  const {dispatch} = store;
  axiosInstance.interceptors.response.use(
    (res) => {
      return res;
    },
    async (error) => {
      console.log('error=', error)
      const originalConfig = error.config;
      // originalConfig._retry使用:避免死循环请求
      if (error.response.status === 401  && !originalConfig._retry) {
        originalConfig._retry = true;
        dispatch(refresh())
        return axiosInstance(originalConfig);
      }
      return Promise.reject(error);
    }
  );
};

export default setup;

authSlices.js

// 使用refresh token 获取 access token
export const refresh = createAsyncThunk('auth/refreshToken', async (params, thunkAPI) => {
  try {
    const {refreshToken} = thunkAPI.getState().auth;
    if (refreshToken) {
      console.log('==== refreshToken ====', refreshToken)
      const response = await axios.post('/auth/oauth/token', qs.stringify({
        grant_type: 'refresh_token',
        refresh_token: refreshToken
      }));
      const resdata = response.data;
      console.log('==== resdata ====', resdata)
      if (resdata.access_token) {
        const refetch = await axios.get('/account/me', {
          headers: {Authorization: `Bearer ${resdata.access_token}`},
        });
        return {
          accessToken: resdata.access_token,
          refreshToken: resdata.refresh_token,
          isLogin: true,
          me: {
            name: refetch.data.name,
            avatar: refetch.data.avatar
          }
        };
      } else {
        return thunkAPI.rejectWithValue({errorMsg: response.data.message});
      }
    } else {
      console.log('==== no refreshToken ====')
      return null
    }


  } catch (error) {
    return thunkAPI.rejectWithValue({errorMsg: error.message});
  }
});


[refresh.fulfilled]: (state, action) => {
      if (action.payload) {
        state.accessToken = action.payload.accessToken;
        state.refreshToken = action.payload.refreshToken;
        state.isLogin = action.payload.isLogin;
        state.me = action.payload.me;
      }
    },

@bjoluc
Copy link
Owner

bjoluc commented Dec 13, 2021

Great, let's re-open this as a feature request anyway – I think it may be useful :)

@bjoluc bjoluc reopened this Dec 13, 2021
@bjoluc bjoluc changed the title how to clear cookie Add defaultState option to remove a cookie for a specified default state Dec 13, 2021
@bryanltobing
Copy link

bryanltobing commented Mar 27, 2022

is there any update on this? I also need to clear cookies when doing logout. Or atleast could we have some workaround to implement logout ?

@bjoluc
Copy link
Owner

bjoluc commented Mar 30, 2022

Hi @bryantobing12,
I didn't pay attention to this lately, but hearing that you're interested, I'm happy to look into it soon 🙂 How important is this to you, or better: When do you need it (feel free to say ASAP, if that's the case)?

@bryanltobing
Copy link

Well, for now it's working fine at my case. And i can clear the cookies manually from the client.

@bryanltobing
Copy link

@bjoluc I was thinking that it would be nice if we can expose decompressFromEncodedURIComponent so that we don't need to install lz-string on our project to decode the cookie data. Is this possible ?

@bjoluc bjoluc closed this as completed in 9f0c224 Aug 22, 2022
github-actions bot pushed a commit that referenced this issue Aug 22, 2022
## [2.2.0](v2.1.2...v2.2.0) (2022-08-22)

### Features

* Add `defaultState` option to remove a cookie for a specified default state ([9f0c224](9f0c224)), closes [#17](#17) [#17](#17)
* Add support for custom serialization functions ([#41](#41)) ([0bae6e9](0bae6e9))

### Bug Fixes

* Avoid redundant Set-Cookie headers in server responses ([8b48978](8b48978))
@github-actions
Copy link

🎉 This issue has been resolved in version 2.2.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request released
Projects
None yet
Development

No branches or pull requests

4 participants