3

I'm currently working on a backend API using Ruby on Rails, Devise, and Devise-JWT, with NextJS on the frontend client, using axios for requests. I've been trying to access the Authorization token from the header (once the user logs in), to then store the token into localhost but it doesn't come within the header on the request. Although, the post login request does supply an Auth on the header when testing on Postman. What am I missing? Thanks in advance!

JeffreyP7
  • 37
  • 3

2 Answers2

1

expose Authorzation header using this: expose : ['Authorization'] in the rack corse config do this:

Rails.application.config.middleware.insert_before 0, "Rack::Cors" do
  allow do
    origins '*'
    resource '*', headers: :any, methods: [:get, :post, :options, :patch, :delete], expose: ['Authorization']
  end
end

https://glaucocustodio.github.io/2016/01/20/dont-forget-to-expose-headers-when-using-rack-cors/

Dyary
  • 753
  • 7
  • 14
0

It would help to see the code you implemented the Axios user auth for the frontend.

But maybe this can help.

//---------- Reducer -----------
// In your reducer
const authReducer = (state, { type, payload }) => {
  switch (type) {
    case 'LOGIN': {
      localStorage.setItem('authToken', JSON.stringify(payload.auth_token));
      localStorage.setItem('authEmail', JSON.stringify(payload.email));
      return {
        authToken: payload.auth_token,
        authEmail: payload.email,
      };
    }
    case 'YOUROTHER': {
      return {  };
    }
    default: {
      
    }
  }
};

export default authReducer;
//-------------------------------

//---------- Contexts -----------
// In your Contexts auth.js file
import authReducer from '../reducers/auth';

const AuthStateContext = React.createContext();
const AuthDispatchContext = React.createContext();

const token = JSON.parse(localStorage.getItem('authToken'));
const email = JSON.parse(localStorage.getItem('authEmail'));
const initialState = {
  isLoggedIn: !!token,
  authToken: token ? token : null,
  authEmail: email ? email : null,
};

const AuthProvider = ({ children }) => {
  const [state, dispatch] = React.useReducer(authReducer, initialState);
  return (
    <AuthStateContext.Provider value={state}>
      <AuthDispatchContext.Provider value={dispatch}>
        {children}
      </AuthDispatchContext.Provider>
    </AuthStateContext.Provider>
  );
};
//-------------------------------

//--------- App.js file ---------
// Then wrap the App.js like:
import { AuthProvider } from './contexts/auth';

function App(props) {
  return (
    <AuthProvider>
      <Main {...props} />
    </AuthProvider>
  );
}
//-------------------------------

//------- Your Login Component -------
// Imports
import { useAuthDispatch } from '../../contexts/auth';

// Axios handler 
const baseUrl = 'http://localhost:3001/';
const login = payload => axios.post(`${baseUrl}api/v1/login`, payload);
const authApi = {
  login,
};

// Auth Header Function
const setAuthHeaders = () => {
  // axios request try this
  axios.defaults.headers = {
    Accept: 'applicaion/json',
    'Content-Type': 'application/json',
  };
  const token = JSON.parse(localStorage.getItem('authToken'));
  const email = JSON.parse(localStorage.getItem('authEmail'));
  //Add token & email to axios header
  if (token && email) {
    axios.defaults.headers['X-Auth-Email'] = email;
    axios.defaults.headers['X-Auth-Token'] = token;
  }
};

// Login 
const Login = () => {
  const [initialValues, setInitialValues] = useState({
    email: '',
    password: '',
  });
  
  const authDispatch = useAuthDispatch();
  //const userDispatch = useUserDispatch();

  const handleLogin = async values => {
    const { /*eg. email, password*/ } = values;
    try {
      const {
        data: { user, /* should include:*/ auth_token },
      } = await authApi.login({ user: { email, password } });
      // your dispatch with payload: auth_token
      authDispatch({ type: 'LOGIN', payload: { auth_token, email } }); // passing the token & email via Dispatch
      // The user: { email, password } comes from the userDispatch
      setAuthHeaders(); // Auth Header Func
    } catch (error) {
      
    };

    return (
      <>
        {/* your jsx code */}
      </>
    );
  }
};

export default Login;

//--- # Your Login Component ---
  • Thanks bud, I've found the issue, rails cors requires one to set the origin domain location, not just the all wild card '*', in order to send the Authorization in the header. It also had to be exposed on cors resource ``` resource '*', headers: :any, expose: %w[Authorization], methods: %i[get post put patch delete options head] ``` – JeffreyP7 Oct 29 '21 at 14:46
  • Great, rails cors did it. I am glad you figured it out. – Zakir Pokrovskii Oct 29 '21 at 23:07