When I see sample apps which uses Apollo-client I see following constructor.When I read HttpLink document, it seems that graphql endpoint must be set as uribut in following code, I couldn't find them.
export const getApolloClient = (): ApolloClient<NormalizedCacheObject> =>
new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({ credentials: 'same-origin', fetch: customFetch }),
});
My question is why this code work well ?
I am totally novice of that, if someone knows this will you please let me know. Thanks
The HttpLink constructor option uri has a default value of /graphql. So as long as that is the correct path it will work without passing a uri option into the constructor.
So your example code:
HttpLink({ credentials: 'same-origin', fetch: customFetch })
is equivalent to
HttpLink({ credentials: 'same-origin', fetch: customFetch, uri: '/graphql' })
Related
So I'm trying to pass an authorization header to Apollo according to the docs on their site.
https://www.apollographql.com/docs/react/networking/authentication/?fbclid=IwAR17YAJ0VA5G8InmAJ_PxcukXKNQxFLFI8aeT4oB7wYE3DjWNaB_F67__zs
However, when I try to log request.headers on my server I don't see the authorization property on there. Next I checked whether or not the function setContext() was being run at all by putting a console.log() within it and found that it didn't run.
const httpLink = new HttpLink({ uri: 'http://localhost:4000' });
const authLink = setContext((request, { headers }) => {
const token = localStorage.getItem('library-user-token')
console.log(token) //doesn't log at all
return ({
headers: {
...headers,
authorization: token ? `Bearer ${token}` : null,
}
})
});
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache()
});
I have almost identical code in my project and it works. Are you passing the client to your ApolloProvider?
How do you batch requests with credentials? I'm using an http-only JWT cookie and HttpLink allows me to pass a credentials: 'include' option which will forward the cookie through to my graphene server. When I try to switch to BatchHttpLink, it no longer accepts that option for configuration. Looking through the source, it doesn't appear there's an easy way to configure this. Anyone know how to handle this?
Here's how I was doing it without batching:
window['app-react'].GRAPHQL_URL = window['app-react'].GRAPHQL_URL || 'http://backend.app.local/graphiql'
const httpLink = new HttpLink({
uri: window['app-react'].GRAPHQL_URL,
credentials: 'include'
})
const client = new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
})
Here's how I wish it worked:
const batchHttpLink = new BatchHttpLink({
uri: window['joor-react'].GRAPHQL_URL,
credentials: 'include'
})
const client = new ApolloClient({
link: batchHttpLink,
cache: new InMemoryCache(),
})
When I do it this way though, the JWT cookie isn't passed in the header.
Right now apollo-link-batch-http is behind in its API compared to apollo-link-http. Here is a note from the docs (as of 2017-12-07)
Note: This package will be updated to remove the dependency on apollo-fetch an use the same options / API as the http-link
Using BatchHttpLink with apollo-fetch
The current API of apollo-link-batch-http requires a custom apollo-fetch if you want to make customizations to things like credentials. Here's a couple of options.
Provide a customFetch to createApolloFetch and define credentials in the fetch options.
Use apollo-fetch middleware
fetch.batchUse(({ options }, next) => {
options.credentials = 'include';
next();
});
I am trying out the new Fetch API but is having trouble with Cookies. Specifically, after a successful login, there is a Cookie header in future requests, but Fetch seems to ignore that headers, and all my requests made with Fetch is unauthorized.
Is it because Fetch is still not ready or Fetch does not work with Cookies?
I build my app with Webpack. I also use Fetch in React Native, which does not have the same issue.
Fetch does not use cookie by default. To enable cookie, do this:
fetch(url, {
credentials: "same-origin"
}).then(...).catch(...);
In addition to #Khanetor's answer, for those who are working with cross-origin requests: credentials: 'include'
Sample JSON fetch request:
fetch(url, {
method: 'GET',
credentials: 'include'
})
.then((response) => response.json())
.then((json) => {
console.log('Gotcha');
}).catch((err) => {
console.log(err);
});
https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials
Have just solved. Just two f. days of brutforce
For me the secret was in following:
I called POST /api/auth and see that cookies were successfully received.
Then calling GET /api/users/ with credentials: 'include' and got 401 unauth, because of no cookies were sent with the request.
The KEY is to set credentials: 'include' for the first /api/auth call too.
If you are reading this in 2019, credentials: "same-origin" is the default value.
fetch(url).then
Programmatically overwriting Cookie header in browser side won't work.
In fetch documentation, Note that some names are forbidden. is mentioned. And Cookie happens to be one of the forbidden header names, which cannot be modified programmatically. Take the following code for example:
Executed in the Chrome DevTools console of page https://httpbin.org/, Cookie: 'xxx=yyy' will be ignored, and the browser will always send the value of document.cookie as the cookie if there is one.
If executed on a different origin, no cookie is sent.
fetch('https://httpbin.org/cookies', {
headers: {
Cookie: 'xxx=yyy'
}
}).then(response => response.json())
.then(data => console.log(JSON.stringify(data, null, 2)));
P.S. You can create a sample cookie foo=bar by opening https://httpbin.org/cookies/set/foo/bar in the chrome browser.
See Forbidden header name for details.
Just adding to the correct answers here for .net webapi2 users.
If you are using cors because your client site is served from a different address as your webapi then you need to also include SupportsCredentials=true on the server side configuration.
// Access-Control-Allow-Origin
// https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api
var cors = new EnableCorsAttribute(Settings.CORSSites,"*", "*");
cors.SupportsCredentials = true;
config.EnableCors(cors);
This works for me:
import Cookies from 'universal-cookie';
const cookies = new Cookies();
function headers(set_cookie=false) {
let headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
};
if (set_cookie) {
headers['Authorization'] = "Bearer " + cookies.get('remember_user_token');
}
return headers;
}
Then build your call:
export function fetchTests(user_id) {
return function (dispatch) {
let data = {
method: 'POST',
credentials: 'same-origin',
mode: 'same-origin',
body: JSON.stringify({
user_id: user_id
}),
headers: headers(true)
};
return fetch('/api/v1/tests/listing/', data)
.then(response => response.json())
.then(json => dispatch(receiveTests(json)));
};
}
My issue was my cookie was set on a specific URL path (e.g., /auth), but I was fetching to a different path. I needed to set my cookie's path to /.
If it still doesn't work for you after fixing the credentials.
I also was using the :
credentials: "same-origin"
and it used to work, then it didn't anymore suddenly, after digging much I realized that I had change my website url to http://192.168.1.100 to test it in LAN, and that was the url which was being used to send the request, even though I was on http://localhost:3000.
So in conclusion, be sure that the domain of the page matches the domain of the fetch url.
Heres my setup:
Ember: 1.1.0-beta.1
Ember-data: 1.0.0-beta.2
# ON STARTUP
APP.ApplicationAdapter = DS.RESTAdapter.extend(
headers: {
'X-API-TOKEN': localStorage.token
}
)
This works fine if they were already logged in when they refresh...
However...
#ON LOGIN FORM SUBMIT ACTION
$.post('/sessions', data).then( (response) =>
if response.token
localStorage.token = response.token
APP.ApplicationAdapter = DS.RESTAdapter.reopen(
headers: {
'X-API-TOKEN': localStorage.token
}
)
else
#set('error_message', response.error)
The calls are still unauthorized, and the adapter keep trying to pass the old token.
So basically the 'headers' property on the adapter is not updated by the 'reopen' method. Whats the proper way to change the adapter in ember-data?
Thanks guys
Once instantiated you should get your adapter from the container.
But since it's not very clear from where you are making the request, try something like this:
#ON LOGIN FORM SUBMIT ACTION
$.post('/sessions', data).then( (response) =>
if response.token
localStorage.token = response.token
adapter = APP.__container__.lookup 'adapter:Rest'
adapter.set('headers', { 'X-API-TOKEN': localStorage.token })
else
#set('error_message', response.error)
Note: using App.__container__ is not recomended for production code depending from where you are making the request it would be more appropriate to get the container in a more clean way.
Update in response to your last comment
In the case you need access to the container in a controller then:
APP.LoginController = Ember.ObjectController.extend
...
adapter = #get('container').lookup 'adapter:application'
adapter.set('headers', { 'X-API-TOKEN': localStorage.token })
...
should get you the adapter.
Hope it helps.
Headers can be used as a computed property to support dynamic headers.
You can use the volatile function to set the property into a non-cached mode causing the headers to be recomputed with every request.
APP.ApplicationAdapter = DS.RESTAdapter.extend(
headers: function() {
return {
'X-API-TOKEN': localStorage.token
};
}.property().volatile()
)
URL's:
toc_headers-customization
method_volatile
I have been using expressjs and mongostore for session management. Following is the code to configure store in expressjs,
app.configure(function(){
app.use(express.session({
secret: conf.secret,
maxAge: new Date(Date.now() + 3600000),
cookie: { path: '/' },
store: new MongoStore(conf.db)
}));
});
I had mentioned the cookie path in the above code. But it sets the cookie in sub.domain.com instead of .domain.com. How do i achieve this?
configure it like this:
app.use(express.session({
secret: conf.secret,
cookie: { domain:'.yourdomain.com'},
store: new MongoStore(conf.sessiondb)
}));
Try to use the following link to configure.
res.cookie('name', 'tobi', { domain: '.example.com', path: '/admin', secure: true });
Link : http://expressjs.com/api.html#res.cookie
This won't work, it throws error.
Error: Most middleware (like session) is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.
app.use(express.session({
secret: conf.secret,
cookie: { domain:'.yourdomain.com'},
store: new MongoStore(conf.sessiondb)
}));
I have a reference link, from where you can take help to set domain in cookie
https://flaviocopes.com/express-cookies/