1

I want to create a react web app containing a login. My backend is implemented with JAX-RS and BASIC authentication. Here is a snippet of the web.xml and a Resource.

<login-config>
    <auth-method>BASIC</auth-method>
</login-config>

<security-constraint>
    <web-resource-collection>
        <web-resource-name>api</web-resource-name>
        <url-pattern>/api/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>ROLE</role-name>
    </auth-constraint>
</security-constraint>

<security-role>
    <role-name>ROLE</role-name>
</security-role>

Resource:

@GET
@PermitAll
@Produces(MediaType.APPLICATION_JSON)
public List<OnlineStackDto> getData() {
    return dataService.getData();
}

All Requests from react are bundled in one file, request.js. Here is the get function as an example.

const user = 'username';
const pass = 'password';

export function get(url) {
    return fetch(url, 
        {
            method: 'GET',
            headers: {
                Authorization: "Basic " + btoa(user + ":" + pass)
            }
        }
    );
}

Of course, hardcoding username and password is not how the app can be deployed later. The function is called like this:

import {get} from "./request";
import React from "react";

export default class DataComponent extends React.Component {
    componentDidMount() {
        get('onlinestacks').then(data => this.setState({myData: data}));
    }
}

The login-logic is realized using react-router and React 16.3 Context-API. Thus, I can access the username/password in every component using a Consumer. Here is an example of how the data is set and used. For a more complete example, see this question.

export default class App extends Component {

    constructor(props) {
        super(props);
        this.state = {
            user: {
                username: '',
                password: ''
            }
        };

        this.login = this.login.bind(this);
    }

    login(username, password) {
        this.setState({
            user: {
                username: username,
                password: password
            }
        });
    }

    render() {
        return (
            <UserContext.Provider value={this.state.user}>
                <Header/>
                /*Other Components*/
            </UserContext.Provider>
        );
    }

}

export default class Header extends React.Component {

    render() {
        return (<header>
            <UserContext.Consumer>{value =>
                <div className="username">{value.username}</div>
            }
            </UserContext.Consumer>
        </header>);
    }
}

My question is:
How can I use username and password from the Context in my requests without having to pass them everytime I want to make a request?

6
  • I can't understand what kind of goal you want to achieve. You want to send some requests with username, and some without? Commented Apr 14, 2018 at 13:31
  • @degr I want to send all requests with username. But the username should not be hardcoded. Instead I want the user to enter his name and use that in all requests Commented Apr 14, 2018 at 13:34
  • You need help with variable assignment? You don't know how to get value from text input and set it into variable? Commented Apr 14, 2018 at 14:03
  • @degr I have the necessary information (username, password) inside the UserContext. I can access it as shown in the Header component. I don't know how to use this data in the request.js file. Just setting it as a global variable feels wrong and the only other way I could think of, is to pass the user as a parameter to the request, like function get(url, user). But this would make it necessary to implement a UserContext.Consumer in every component which needs to fetch data. This feels unnecessarily complicated. Commented Apr 15, 2018 at 6:18
  • Can you give an example where you call request method? The proposed solution would depend on that. There are many ways to do it and each has its own drawbacks. Commented Apr 15, 2018 at 13:04

1 Answer 1

1

There are many possible solutions to this. You can use bind method and pass a bound get method with username and password set. So you get function will accept username and password as parameters

export function get(username, password, url)

And you Context.Provider will pass bound function

<UserContext.Provider value={get.bind(null,this.state.user,this.state.password)}>

To not trigger reflows you can lift the binding

login(username, password){
  this.setState({
        authenticatedGet: get.bind(null,username,password)
  });
}
//....
<UserContext.Provider value={this.state.authenticatedGet}>

I really don't think that you should use Context for this kind of stuff though. The thing is Context is good for UI logic and this is more about service layer. There are many other solutions including passing get as prop where appropriate, or if you use redux with redux-thunk pass it as thunk.withExtraArgument but this is really out of scope for your question.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your answer! Thinking about it, I came to the conclusion that you are right, and Context should not be used for that. Now, I'll implement a solution with cookies.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.