-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Re-authenticate and re-fetch Customer-data with auth-token. #2940
Comments
Here are the HttpLink and Middleware/Afterware for the Apollo-client: /////////////// HTTP LINK SETUP ////////////////////////
// Get the API host, port, and path from the environment
const { apiHost, apiPort, shopApiPath } = environment;
// Define the GraphQL API URI
const uri = `${apiHost}:${apiPort}/${shopApiPath}`;
/**
* HTTP options
*/
const httpOptions: Options = {
uri: () => {
if (languageCode) {
return `${uri}?languageCode=${languageCode}`;
} else {
return `${uri}`;
}
},
};
/**
* HTTP link handler
*/
const httpLinkHandler = httpLink.create(httpOptions);
/////////////// AFTERWARE & MIDDLEWARE SETUP ////////////////////////
/**
* Afterware which sets the auth token in localStorage
*/
const afterware = new ApolloLink((operation, forward) => {
return forward(operation).map((response) => {
// Apollo operation context
const context = operation.getContext();
// Auth header
const authHeader: string =
context.response.headers.get('vendure-auth-token');
// Check if the auth header is present and the platform is the browser
if (authHeader && isPlatformBrowser(platformId)) {
// If the auth token has been returned by the Vendure
// server, we store it in localStorage
localStorage.setItem(AUTH_TOKEN_KEY, authHeader);
}
return response;
});
});
/**
* Auth middleware which sets the auth token in the request headers
*/
const auth = new ApolloLink((operation, forward) => {
// Check if the platform is the browser
if (isPlatformBrowser(platformId)) {
// Get the auth token from localStorage
const authToken = localStorage.getItem(AUTH_TOKEN_KEY);
if (authToken) {
// Set the operation context
operation.setContext({
// Set the auth token in the request headers
headers: channelToken
? new HttpHeaders()
.set('Authorization', `Bearer ${authToken}`)
.set('vendure-token', channelToken)
: new HttpHeaders().set('Authorization', `Bearer ${authToken}`),
});
}
}
return forward(operation);
}); At the end of the factoryFunction for Apollo-client: // Return Apollo client options
return {
credentials: 'include', // 'same-origin' | 'include' | 'omit
cache: cache,
link: ApolloLink.from([auth, afterware, httpLinkHandler]),
ssrForceFetchDelay: 500,
ssrMode: true,
}; Apollo-client provider setup: /**
* Apollo client provider
*/
const APOLLO_CLIENT_PROVIDER: FactoryProvider = {
provide: APOLLO_OPTIONS,
useFactory: apolloOptionsFactory,
deps: [HttpLink, TransferState, PLATFORM_ID],
};
/**
* Apollo providers
*/
export const apolloProviders: ApplicationConfig['providers'] = [
Apollo,
APOLLO_CLIENT_PROVIDER,
]; |
OK. I solved it. It was the Apollo-Angular Client Hydration for SSR that prevented the auth-session: if (isBrowser) {
// Get the state from the transfer state
const state = transferState.get(STATE_KEY, {});
// Restore the Apollo cache
cache.restore(state);
} else {
// Serialize the Apollo cache
transferState.onSerialize(STATE_KEY, () => {
return cache.extract();
});
// Reset cache after extraction to avoid sharing between requests
cache.reset();
} I believe the Client Hydration is useful for SSR but apparently the documented way breaks the querying logic. |
Extra explanation after investigation: Apparently what happened was that due to Hydration, the queries were run on server-side and when client-side is rendered, those queries get hydrated from cache, but since the auth-token was in localstorage, the server-side activeCustomer-query could not get the session and then the client-side query got null-response as well. It might work if there was someway to handle the auth-token on server side. |
Just for reference: storing authentication tokens in localStorage is not considered secure. It's better to store it as a cookie. https://medium.com/@coderoyalty/should-you-store-sensitive-tokens-in-localstorage-ce13698676f3 |
So Vendure's own documentation instructs this bad habit? localStorage is used in these examples: |
IMO there is some nuance here: In the linked article the author gives 2 scenarios that localstorage is vulnerable to:
But then in the cookie section, XSS is also a vulnerability for cookies, which the author says "utilize secure web development frameworks and libraries that offer built-in protections against XSS attacks, such as AngularJS, React, and Vue.js.". But the same applies to localstorage. On balance I'd say that cookies have the edge over localstorage when used with httponly, secure & samesite options. But the major disadvantage is that they can be really troublesome when your API is on a different domain to your client app, which is very common with headless projects. |
Is your feature request related to a problem? Please describe.
I have the Apollo Client set up with cache persistence and the middleware/afterware handling the auth-token to/from LocalStorage, but when doing page refresh, the authenticated state is lost even when the token clearly is still saved.
Then the activeCustomer-query returns null, even though the query request has the auth-token in the headers.
As said in Vendure's documents, the activeCustomer-query only works for registered and logged-in Customers.
So how do I fetch that data with the saved auth-token since I cannot automatically do a login-mutation which requires email/password -input?
Describe the solution you'd like
A new mutation that re-authenticates the user with the saved auth-token and then returns the user (Customer) data.
Describe alternatives you've considered
Extend activeCustomer to optionally take in the auth-token as a parameter and return the data if the auth-token is valid.
Additional context
Basically the issue here is that after I have registered and logged-in as a Customer, I have to re-login every single time if I refresh page or when VS Code does it when saving code-changes.
If the issue is with Apollo Client -configuration, I'd appreciate an example of a working solution for persisting the auth-state.
EDIT: As a side-note, how is the "rememberMe"-field supposed to work?
I set it as true when logging in but it does not show in the database or in the Customers data.
How is it supposed to remember my login or credentials?
The text was updated successfully, but these errors were encountered: