-
Notifications
You must be signed in to change notification settings - Fork 47
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
How do you use authMiddleware? #6
Comments
Just provide Relay.injectNetworkLayer(new RelayNetworkLayer([
authMiddleware({
token: () => window.MyGlobalVarWithToken, // store.get('jwt'),
}),
])); |
thanks, I will use AsyncStorage. calling it every time is not a problem? |
I don't sure that So if possible, try to put token in some variable with sync access. BTW don't forget about At the end, you may write your own middleware for working with your token logic. As example you may see this simple MW: https://github.com/nodkz/react-relay-network-layer/blob/master/src/middleware/perf.js |
thanks for all the help, I will try to write a middleware |
Few minutes ago I publish new version, where was added This can help you, if you do requests to graphql server without token and don't want send empty auth header. |
it could be very useful if we could just call a function on authMiddleware to save the token or remove it |
Assumption: Current realization: I try keep MW realization as simple, as possible. If I begin store token internally, I should also provide functions for reading and removing token ;). |
I think it is better to use Relay.Environment to reset relay data on login, thanks for all the support |
How I actually use auth middleware: class ClientApi {
...
getRelayNetworkLayer = () => {
return new RelayNetworkLayer([
authMiddleware({
token: () => this._token,
tokenRefreshPromise: () => this._getTokenFromServer(this.url('/auth/jwt/new')),
}),
...
} refresh token promise has the following view _getTokenFromServer = (url, data = {}) => {
console.log('[AUTH] LOAD NEW CABINET JWT');
const opts = {
method: 'POST',
headers: {
'Accept': 'application/json', // eslint-disable-line
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
};
return fetch(url, opts)
.then(res => {
if (res.status > 299) { throw new Error(`Wrong response status ${res.status}`); }
return res;
})
.then(res => res.json())
.then(json => {
this._token = json.token;
this._saveTokenToStorage();
return this._token;
})
.catch(err => console.error('[AUTH] ERROR can not load new cabinet jwt', err));
}; So if new user makes request to server, it responds with 401 header. AuthMW implicitly catchs this header and run So app logic does not know anything about authorization. Our Our ClientApi class was written inspired by https://github.com/reindexio/reindex-js/blob/master/src/index.js |
for every 401 it will try to get the token? how the problem with this approach is that you do not clean the Relay cache, so if an user logged in, then logout, and another user login, this second user could have access to some left data from the first user |
Yep, for every 401 request it tries to refresh token calling
In my case I just reload page after |
reload a page is not a good user experience, and it does not work on react native either |
Also trying to solve this issue on React Native. Did anyone successfully implement a solution for pre-register -> post-login Relay? |
Happy to keep this (work in progress) React Native sample public as a template, but how to fix the middleware implementation? Update: condensed the code question to a gist https://gist.github.com/allpwrfulroot/6b6b58ee2a3efebf138f00714c63630b |
@sibelius, to address the problem avoiding page refresh, the solution provided by Relay is to create a new Store (see RelayEnvironment) which clean all the cache and avoid one user to see data it should not. |
This could be useful to easily reset a RelayEnvironment class RelayStore {
constructor() {
this._env = new Environment();
this._networkLayer = null;
this._taskScheduler = null;
RelayNetworkDebug.init(this._env);
}
reset(networkLayer) {
// invariant(
// !this._env.getStoreData().getChangeEmitter().hasActiveListeners() &&
// !this._env.getStoreData().getMutationQueue().hasPendingMutations() &&
// !this._env.getStoreData().getPendingQueryTracker().hasPendingQueries(),
// 'RelayStore.reset(): Cannot reset the store while there are active ' +
// 'Relay Containers or pending mutations/queries.'
// );
if (networkLayer !== undefined) {
this._networkLayer = networkLayer;
}
this._env = new Environment();
if (this._networkLayer !== null) {
this._env.injectNetworkLayer(this._networkLayer);
}
if (this._taskScheduler !== null) {
this._env.injectTaskScheduler(this._taskScheduler);
}
RelayNetworkDebug.init(this._env);
}
// Map existing RelayEnvironment methods
getStoreData() {
return this._env.getStoreData();
}
injectNetworkLayer(networkLayer) {
this._networkLayer = networkLayer;
this._env.injectNetworkLayer(networkLayer);
}
injectTaskScheduler(taskScheduler) {
this._taskScheduler = taskScheduler;
this._env.injectTaskScheduler(taskScheduler);
}
primeCache(...args) {
return this._env.primeCache(...args);
}
forceFetch(...args) {
return this._env.forceFetch(...args);
}
read(...args) {
return this._env.read(...args);
}
readAll(...args) {
return this._env.readAll(...args);
}
readQuery(...args) {
return this._env.readQuery(...args);
}
observe(...args) {
return this._env.observe(...args);
}
getFragmentResolver(...args) {
return this._env.getFragmentResolver(...args);
}
applyUpdate(...args) {
return this._env.applyUpdate(...args);
}
commitUpdate(...args) {
return this._env.commitUpdate(...args);
}
/**
* @deprecated
*
* Method renamed to commitUpdate
*/
update(...args) {
return this._env.update(...args);
}
}
const relayStore = new RelayStore(); just call: |
I prefer to solve the problem by simply storing the instance of the environment in a singleton and provide a method to refresh the environment as it avoids a lot of code duplication. import Relay from 'react-relay';
import {
RelayNetworkLayer,
authMiddleware,
urlMiddleware,
} from 'react-relay-network-layer';
let instance = null;
const tokenRefreshPromise = () => ...;
const refresh = () => {
instance = new Relay.Environment();
instance.injectNetworkLayer(new RelayNetworkLayer([
urlMiddleware({
url: '<some_url>',
batchUrl: '<some_batch_url>',
}),
next => req => next(
// Retrieve token info and assign it to req
),
authMiddleware({
allowEmptyToken: true,
token: req => req.token,
tokenRefreshPromise,
}),
], { disableBatchQuery: true }));
return instance;
};
const getInstance = () => (instance || refresh());
export default {
getCurrent: getInstance.bind(this),
refresh: refresh.bind(this),
}; Then you can import this file as Store and pass it to your RelayRenderer as Store.getInstance() and when you need to refresh your data after a logout for instance, just include Store in your file and call Store.refresh(), it generates a new instance and updates it everywhere. |
This is how I'm doing it:
|
|
I want to set the auth token after login/register process using the token received
is it possible? do u have an example?
The text was updated successfully, but these errors were encountered: