I’m trying to set an authorization middleware yo my Apollo Client but something is not working. I can set the corresponding header correctly but my server still responds as i’m not authenticated.
Tried this:
const httpLink = new HttpLink({
uri: process.env.API_GRAPHQL,
});
const authLink = setContext((_, { headers }) => {
// get the authentication token from local storage if it exists
const token = localStorage.getItem("token");
// return the headers to the context so httpLink can read them
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : "",
},
};
});
const apolloClient = new ApolloClient({
link: authLink.concat(httpLink),
includeUnusedVariables: true,
credentials: "include",
connectToDevTools: true,
cache: new InMemoryCache({})
And this:
const httpLink = new HttpLink({
uri: process.env.API_GRAPHQL,
});
const authMiddleware = new ApolloLink((operation, forward) => {
var token = localStorage.getItem("token");
operation.setContext({
headers: {
Authorization: token ? `Bearer ${token}` : "",
},
});
console.log(operation);
return forward(operation);
});
const apolloClient = new ApolloClient({
link: authMiddleware.concat(httpLink),
includeUnusedVariables: true,
credentials: "include",
connectToDevTools: true,
cache: new InMemoryCache({})
I’ve also tried with createHttpLink instead of new httpLink, and with concat(middleware, httpLink) instead of middleware.concat(httpLink).
The sent request has correctly set the token, but the response is still an auth error.
If i do not set any middleware and hard-code my token the Client works fine, something in the construction of my link is not working…
Is there something i’m missing? what are my possibilities? Is there a way I can debug my client?
Thank’s in advance.
Related
when put token value as hardcoded it's work properly,but when i got token from asyncstorage and pass token in headers i got this error
Response not sucessful:Recevied status code 500 What is wrong in mycode?
import { ApolloClient,ApolloProvider,InMemoryCache,gql } from '#apollo/client'
import { createUploadLink } from 'apollo-upload-client'
const getToken = async () => {
const token = await AsyncStorage.getItem('#storage_Key')
return token
}
const token = getToken()
const client = new ApolloClient({
link: createUploadLink({
uri: 'http://192.168.1.82:8080/graphql',
headers: {
authorization: token
}
}),
cache: new InMemoryCache()
})
When I add authorizan in headers I got this Error:Response not sucessful:Received status code 500 In React native otherwise it's work perfectly . What is issue here?
Can you try then function for async function
getToken().then((token) => {
const client = new ApolloClient({
link: createUploadLink({
uri: 'http://192.168.1.82:8080/graphql',
headers: {
authorization: token
}
}),
cache: new InMemoryCache()
});
});
I'm using Apollo Client as a graphql client on my next.js application, Here is the function that creates a client for me:
let client: ApolloClient<any>;
export const __ssrMode__: boolean = typeof window === "undefined";
export const uri: string = "http://localhost:3001/graphql";
const createApolloClient = (): ApolloClient<any> => {
return new ApolloClient({
credentials: "include",
ssrMode: __ssrMode__,
link: createHttpLink({
uri,
credentials: "include",
}),
cache: new InMemoryCache(),
});
};
Surprisingly, when I make a mutation to the graphql server I'm able to set the cookies but, I'm not able to get the cookies from the client. What may be possibily the problem?
I came to the same problem, my solution was to create a client every time a server-side rendering is made, maybe it's not ideal to have a client to execute GraphQL calls in the browser and others in the server but it's what worked best for me. This is the code:
import { ApolloClient, createHttpLink, InMemoryCache } from '#apollo/client';
import { NextPageContext } from 'next';
import { setContext } from '#apollo/client/link/context';
export const httpLink = createHttpLink({
uri: 'http://localhost:4000/graphql',
credentials: 'include',
});
const CreateClient = (ctx: NextPageContext | null) => {
const authLink = setContext((_, { headers }) => {
return {
headers: {
...headers,
cookie:
(typeof window === 'undefined'
? ctx?.req?.headers.cookie || undefined
: undefined) || '',
},
};
});
return new ApolloClient({
credentials: 'include',
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
ssrMode: true,
});
};
export default CreateClient;
So, what I do is pass the context from the getServerSideProps and see if I have some cookies there, if so I just set the cookies, you can also send the authorization token if it's in the cookie. To call it is very simple:
export async function getServerSideProps(context: NextPageContext) {
const client = CreateClient(context);
const { data } = await client.query({
query: SOME_QUERY,
});
return {
props: {
data,
},
};
}
You can also do a HOC as in the Ben Awad tutorial Apollo Client HOC but I think it was too much for what I was trying to do. Hope it helped you or helps someone there :)
Also, I'm using Next 12.1.5 and React 18
I have a vue web app from which I'm trying to run a subscription using a hasura query.
My problem is that I cannot pass to the Websocket request an authorization token as the backend expects.
These are my current settings:
const token = localStorage.getItem("token") || null;
const options = {
httpUri: //graphql http entpoint,
wsUri: //graphql ws endpoint
};
let link = new HttpLink({
uri: options.httpUri
});
// Create the subscription websocket link if available
if (options.wsUri) {
const wsLink = new WebSocketLink(
new SubscriptionClient(options.wsUri, {
lazy: true,
reconnect: true,
connectionParams: {
headers: {
Authorization: `Bearer ${token}`
}
}
})
);
// using the ability to split links, you can send data to each link
// depending on what kind of operation is being sent
link = split(
// split based on operation type
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === "OperationDefinition" &&
definition.operation === "subscription"
);
},
wsLink,
link
);
}
const authLink = setContext((_, { headers }) => {
// return the headers to the context so httpLink can read them
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : ""
}
};
});
const errorLink = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors)
graphQLErrors.map(({ message }) => {
if (message.includes("unauthorized")) {
EventBus.$emit("unauthorized");
}
});
if (networkError) console.log(`[Network error]: ${networkError}`);
});
const apolloClient = new ApolloClient({
link: ApolloLink.from([errorLink, authLink, link]),
cache: new InMemoryCache(),
connectToDevTools: true
});
const apolloProvider = new VueApollo({
defaultClient: apolloClient
});
When I try to run the subscription I get
HTTP Authentication failed; no valid credentials available
And in the ws request header I cannot see my Authorization bearer set.
A side info I need authorization for both http and ws requests
I think errorLink or authLink unexpectedly change websocket header token. You try modifying a bit:
const httpLink = from([
authLink,
// errorLink,
new HttpLink({
uri: Config.httpDataHost,
headers: {
[XHasuraClientName]: Config.hasuraClientName
}
})
]);
const wsLink = new WebSocketLink({ ... });
const link = ...
const apolloClient = new ApolloClient({
link: ApolloLink.from([errorLink, link]),
cache: new InMemoryCache(),
connectToDevTools: true
});
If it doesn't work, you can try commenting errorLink to check. Another thing is, you shouldn't get token globally, but use lazy function so ApolloClient can always get latest access token from local storage
const getIdToken = () => localStorage.getItem('token') || null;
const wsLink = new WebSocketLink({
uri: options.wsUri,
options: {
connectionParams: () => ({
headers: {
Authorization: getIdToken(),
}
}),
...
}
});
PS: I have an example repository with React + Apollo Client 3.0. Although you are using Vue.js,Apollo Client construction is the same https://github.com/hgiasac/ra-hasura-typescript-boilerplate/blob/auth-jwt/src/shared/ApolloClient.ts
I am trying to set the cookie on fetch or axios, I already checked the solutions posted on github or stackoverflow, but none of them are working now.
I'm using Saml for authentication on my RN project.
So Here are stories:
on the first login, if the user clicks the start button, it calls the api of get profile info, if there is no cookie on header, it returns redirect url and also cookie(it's unauth cookie), and go to the url on the webview, after the user logins on the webview, then the original url(get profile api) is called on webview, after that, I'd grab the auth cookie using react-native-cookies library, and then set it on the header of fetch/axios. but it doesn't work.
export async function getMyProfile() {
const cookies = await LocalStorage.getAuthCookies();
await CookieManager.clearAll(true)
const url = `${Config.API_URL}/profiles/authme`;
let options = {
method: 'GET',
url: url,
headers: {
'Content-Type': 'application/json',
},
withCredentials: true
};
if (cookies) options.headers.Cookie = cookies.join(';')
return axios(options)
.then(res => {
console.info('res', res);
return res;
}).catch(async (err) => {
if (err.response) {
if (err.response.status === 401) {
const location = _.get(err, 'response.headers.location', null);
const cookie = _.get(err, 'response.headers.set-cookie[0]', null);
await LocalStorage.saveUnAuthCookie(cookie);
return { location, cookie, isRedirect: true };
}
}
});
}
You could use Axios interceptor.
let cookie = null;
const axiosObj = axios.create({
baseURL: '',
headers: {
'Content-Type': 'application/json',
},
responseType: 'json',
withCredentials: true, // enable use of cookies outside web browser
});
// this will check if cookies are there for every request and send request
axiosObj.interceptors.request.use(async config => {
cookie = await AsyncStorage.getItem('cookie');
if (cookie) {
config.headers.Cookie = cookie;
}
return config;
});
well i have a problem i tried to connect an api with basic authorization but the server don´t give me access it return a 401(unautorized) my code is:
getApi() {
console.log('here i am in the method for get extensions');
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Basic ***********************'
});
const options = {
headers,
withCredentials: true
};
// tslint:disable-next-line:max-line-length
return this.http.post('https://10.100.43.241/json', this.jsonBody, options).map((response: Response) => {
const resToJSON = JSON.stringify(response);
console.log('i am going to return jsonfrom method');
return resToJSON;
});
}
i tried too with postman an it is working as well. i really need to know how can i solved this problem of connection or authorization
note: i am not the administrator about the server
Try this architecture.
Component:
this._appApiService.getApi(this.jsonBody).subscribe(result => {
this.resToJSON = result;
});
Service:
getApi(jsonBody: any) {
// add authorization header with jwt token
let headers = new HttpHeaders({ 'Authorization': 'Bearer ' + this.token });
let options = { headers: headers };
return this.http.post(this.baseUrl + 'https://10.100.43.241/json', this.jsonBody , options);
}