Apollo Client: Send different headers relative to authentication/authorization - graphql

I will often have an expired authorization token in my app.
I do not, however, want this error to block requests that do not require authorization. What is the work around?
I'd like to customize my headers for requests to simply view a page (which doesn't require token, so send with an empty header) and for requests to edit data (add token and allow error to block request).
An invalid token, with headers set like below for every request, is now blocking the simple fetching of open data:
const client = new ApolloClient({
uri: "http://localhost:8000/graphql",
request: operation => {
const token = sessionStorage.getItem('jwtToken');
operation.setContext({
headers: {
'x-token': token || '',
},
});
},
});

Related

MSAL and OAuth 2.0 - Request an authorization code programmatically

Goal is to get access token from MSAL programmatically for Cypress e2e tests.
We use V2.0 API.
According to this I first need to get the authorization code: https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#request-an-authorization-code
to get the access token https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#request-an-access-token
So in order to get authorization code I would need to do this request
// GET
// Line breaks for legibility only
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&response_type=code
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&response_mode=query
&scope=openid%20offline_access%20https%3A%2F%2Fgraph.microsoft.com%2Fmail.read
&state=12345
&code_challenge=YTFjNjI1OWYzMzA3MTI4ZDY2Njg5M2RkNmVjNDE5YmEyZGRhOGYyM2IzNjdmZWFhMTQ1ODg3NDcxY2Nl
&code_challenge_method=S256
But this returns text/html so I would need to manually login to get the code.
Is there any way to progammatically to get the authorization code?
This is how I got it solved by creating a login command. The command fetches the token programatically and stores it into localStorage.
import 'cypress-localstorage-commands';
Cypress.Commands.add('login', () => {
const request = {
method: 'POST',
form: true,
url: `https://login.microsoftonline.com/${Cypress.config('tenantId')}/oauth2/v2.0/token`,
body: {
grant_type: 'client_credentials',
client_id: Cypress.config('clientId'),
client_secret: Cypress.config('clientSecret'),
scope: `${Cypress.config('clientId')}/.default`,
},
};
cy.request(request).then(response => cy.setLocalStorage('msal.idtoken', response.body.access_token));
});

Ruby rest-client 401 Unauthorized after post of data

I'm new to using the rest-client. I know I'm missing something, but I am trying to do the following:
Post to a login endpoint to authenticate
After authentication, post csv text to another endpoint that requires a logged in user
The authentication portion is successful, however, I am getting a 401 Unauthorized when step 2 occurs.
rest_client = RestClient
login_response = #global_rest_client.post(
host + 'LOGIN ENDPOINT',
{ userName: 'user', password: 'password'},
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
)
import_response = rest_client.post(
host + 'IMPORT DATA ENDPOINT',
headers: { 'X-System-Name': 'AndroidMobile', 'Content-Type': 'multipart/form-data },
csv: csv_string
)
My understanding of how authentication works could be wrong. My assumption is that as long as the same instance of the client has a successful login, then the post of csv data would also be successful.
I appreciate any input.
HTTP (1.1) is stateless so a request does not contain any information about previous requests unless that information is encoded and added to the request in some way (e.g. cookies or headers). So when you make your import request the server does not know if/that you are authenticated even though you just made a login request.
You'll have to include the token you receive from your login request in subsequent requests. This should go in the 'Authorization' header.
For example:
auth_token = login_response["success"]["token"] # or whatever the key is for the token
import_response = rest_client.post(
host + 'IMPORT DATA ENDPOINT',
headers: { 'Authorization': "Bearer #{auth_token}", 'X-System-Name': 'AndroidMobile', 'Content-Type': 'multipart/form-data },
csv: csv_string
)
The way authentication works depends on the server and can be different in different cases. So the site you are accessing might expect the Authorization header to be like "Token #{auth_token}" or anything else, but they should mention it in their documentation.

CORs error when accessing Square V2 API

I'm making a client-side request out to V2 of the Square API using Vue and Axios. My Vue component is as follows:
import axios from 'axios';
export default {
mounted() {
var instance = axios.create({
baseURL: 'https://connect.squareup.com/v2/',
timeout: 1000,
headers: {
'Authorization': 'Bearer xxxxxxxxxxxxxxxxx',
'Accepts': 'application/json',
'Content-Type': 'application/json'
}
});
instance.get('catalog/list')
.then(function (response) {
console.log(response);
}) ;
}
}
However, when I make that call, I receive the following error:
Failed to load https://connect.squareup.com/v2/catalog/list: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://local-env.dev' is therefore not allowed access. The response had HTTP status code 403.
That error suggests that there is some configuration that has to happen on the Square side, but I saw no opportunity to whitelist domains, etc.
Has anyone come across this error before, regardless of service, and if so, how did you resolve?
I don't think the Square API supports being called from a browser. I used Postman to do an OPTIONS request on https://connect.squareup.com/v2/catalog/list and the response was a NOT_FOUND. The OPTIONS request is needed for proper CORS support.
Plus, if you did this, I would think your auth token would need to be sent to the client -- thus exposing it to everyone. It looks like the Square API is only designed to be called from a server. But that is just based on me skimming the docs a bit. I have no experience using their API.
When doing OAuth authorization request you are not supposed to do it from your application. Create and URL with the parameters and open it in a new browser window or tab, Something like:
const grants='MERCHANT_PROFILE_READ CUSTOMERS_READ CUSTOMERS_WRITE PAYMENTS_READ PAYMENTS_WRITE PAYMENTS_WRITE_ADDITIONAL_RECIPIENTS PAYMENTS_WRITE_IN_PERSON';
const params = new HttpParams()
.set('scope', grants)
.set('client_id', <YourSquareApplicationId>)
.set('state', '1878789');
const requestUrl = `${<squareUrl>}/oauth2/authorize?${params.toString()}`;
window.open(requestUrl, "_blank");
That new window is supposed to ask the end user to login to his account and accept or deny the request.

Ionic 2 ASP APi token request

I'm Trying to retrieve a bearer token from my ASP API from my ionic2 app.
I have enabled CORS on the API as shown below:
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
This enabled me to form a POST request from my ionic 2 app to my API in order to register a user. This works wonderfully.
The request I used for this is as shown below:
let headers = new Headers({
'Content-Type': 'application/json'
});
let options = new RequestOptions({
headers: headers
});
let body = JSON.stringify({
Email: credentials.email,
Password: credentials.password,
ConfirmPassword: credentials.confirmPassword
});
return this.http.post('http://localhost:34417/api/Account/Register', body, options)
However when I try to retrieve a token from my API I receive the following error:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8100' is therefore not allowed access.
The request I'm using to try and retrieve the token is as follows:
let body = "grant_type=password" + "&userName=" + credentials.email + "&password=" + credentials.password;
let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
let options = new RequestOptions({ headers: headers });
return this.http.post('http://localhost:34417/token', body, options)
This is the only request that is throwing this error, all other requests to my API work fine.
Have I missed anything, or am I doing something wrong?
var cors = new EnableCorsAttribute("*", "*", "*");
Looks like you are setting Access-Control-Allow-Origin as *.
Check MDN CORS Requests with credentials.
Credentialed requests and wildcards
When responding to a credentialed request, the server must specify an
origin in the value of the Access-Control-Allow-Origin header, instead
of specifying the "*" wildcard.
You will have to set a specific url if you use credentials.
Or if you only intend to use only for ionic 2, you could avoid the cors issue by setting a proxy.
According to the official blog:
The proxies settings contain two things: the path you use to access them on your local Ionic server, and the proxyUrl you’d ultimately like to reach from the API call.
{
"name": "ionic-2-app",
"app_id": "my_id",
"proxies": [
{
"path": "/api",
"proxyUrl": "http://localhost:34417/api"
}
]
}
Ionic serve command by default will start server on localhost:8100.
The set proxy will hit your http://localhost:34417/api.
Your path in the requests will be to the localhost:8100/api instead of your actual server.

Cookie is "undefined" in Koa/Express request

I'm using Koa JS framework for jwt authentication.
So basically when the user signs in, I set a jwt token (signed) to user's browser cookie, which seems to work fine as shown below (Chrome cookie settings):
(www.localhost.com instead of localhost is because I edited my hostfile, but this should have no effect in setting/getting cookies)
The problem, however, is when I send a POST request to my local Koa server, the jwt cookie is undefined. All I'm doing to verify the token is this:
routes.js
const Router = require("koa-router");
const router = new Router();
router.post(`api/authenticate`, function* () {
const jwt = this.cookies.get("jwt", { signed: true }); //jwt is undefined!!
if (!jwt)
this.throw("Invalid or expired token!");
this.status = 200;
});
//...
app.use(router.routes());
app.use(router.allowedMethods());
Here, this.cookies.get("jwt") returns undefined. The POST request is sent using AXIOS library with "withCredentials: true" header and a valid CSRF token:
authenticate.js
axios.post("api/authenticate", {}, {
headers: {
"X-Requested-With": "XMLHttpRequest",
"X-CSRF-Token": "A VALID CSRF TOKEN GENERATED BY SERVER",
"Content-Type": "application/json",
},
withCredentials: true,
});
Can anyone help me find out why this.cookies.get fails to fetch cookie from a simple POST request? I'm simply posting to my localhost, so I believe this is not a CORS problem.
What is more strange is that when I check my chrome developer tool, the "jwt" and "jwt.sig" tokens are successfully included in the request header..
Any help would be appreciated.
Update: Setting the cookie
//...
this.cookies.set("jwt", "SOME JWT GENERATED BY SERVER", {
httpOnly: true,
signed: true,
});
//...

Resources