how to get token when sign up using graphql in flutter - flutter

hello i am trying to get the token value when user is signing up. i am running mutation query for signing up a new user but my problem is i don't know how to get the token when sign up is successful.
this is the api endpoint https://agro-e-commerce.herokuapp.com/graphql
and this is my mutation query in graphql playground
mutation{
signUp(data: {
full_name:"",
user_name:"",
email:"",
phone:"",
password:"",
division:"",
region:"",
address:""
}){
token}
}
here is my code in flutter
String query0 = """
mutation run(\$full_name: String!,\$user_name:String!,\$email:String!,
\$phone: String!,\$password: String!,\$division: String!,\$region:String!,\$address: String!){
signUp(data:{
full_name:\$full_name
user_name:\$user_name,
email:\$email,
phone:\$phone,
password:\$password,
division:\$division,
region:\$region,
address:\$address
}){
token
}
}
body: new Mutation(
builder: (RunMutation runMutation, QueryResult result) {
return FloatingActionButton(
child: new Icon(Icons.add),
onPressed: () {
runMutation({
'user_name': 'anikkoll',
'full_name': 'anikk karmokerkll',
'email': 'anikjkoy78749kl#gmail.com',
'phone': '0167605672879',
'password': 'password',
'division': 'barishal',
'region': 'barishal sadar',
'address': 'kawnia'
});
},
);
},
options: MutationOptions(document: query0),
onCompleted: (resultdata) {
print(resultdata);
}
i expected only token but i got this
{signUp: {token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjgzYTQzMzJhLTk2OWQtNDI3Mi05OWY3LTdiOWNjN2ZlNDhkOCIsImVtYWlsIjoiYW5pa2prb3k3bDg3NDlrbEBnbWFpbC5jb20iLCJ1c2VyX25hbWUiOiJhbmlra29vbGwiLCJyb2xlIjoiQ09OU1VNRVIiLCJpbWFnZSI6bnVsbCwiZnVsbF9uYW1lIjoiYW5pa2tsIGthcm1va2Vya2xsIiwicGhvbmUiOiIwMTU3NjA1NjcyODc5IiwiYWRkcmVzcyI6Imthd25pYSIsInJlZ2lvbiI6ImJhcmlzaGFsIHNhZGFyIiwiZGl2aXNpb24iOiJiYXJpc2hhbCIsImlhdCI6MTU2MzE3ODkxOSwiZXhwIjoxNTYzNzgzNzE5fQ.qCpES_c-dtk7nr-EXqTbTWjIdj4OMqB2HBsEwFXDMlc}}

In your query, you are requesting only the token. In return, you got your token.
This is the token you want now you just have to decode it.

Related

How could i pass cookies in Axios

I am in a next-js app and my auth token is stored in cookies.
For some raisons i use Swr and Api route to fetch my secured api backend.
i am trying to find a way to put my auth token in all api request.
During login cookie is set
res.setHeader(
'Set-Cookie',
cookie.serialize('token', data.access_token, {
httpOnly: true,
secure: process.env.NODE_ENV !== 'development',
maxAge: data.expires_in, // 1 week
sameSite: 'strict',
path: '/',
}),
);
This is an example of a page using swr fetch
//page/test.ts - example of my test route
const { data, error } = useFetchContent(id);
if (error) {
showError('error');
replace('/');
}
return <DisplayContent content={data} />
This is a swrFetchHook
// fetchContentHook
function useFetchContent(id: string): ContentDetail {
return useSWR<any>(`/api/content/${id}`, fetcherApiRoute);
}
const fetcherApiRoute = (url: string): Promise<any> => {
return axios(url)
.then((r) => r.data)
.catch((err) => {
console.info('error is ', err)
throw err
});
};
export default useFetchContent;
inside api route
export default async (req, res): Promise<ContentDetail> => {
const { id } = req.query;
if (req.method === 'GET') {
const fetchRealApi = await apiAxios(url);
if(fetchRealApi) {
// here depending on result of fetchRealApi i add some other fetch ...
return res.status(200).json({ ...fetchRealApi, complement: comp1 });
}
return res.status(500)
}
return res.status(500).json({ message: 'Unsupported method only GET is allowed' });
};
and finally api axios configuration
const apiAxios = axios.create({
baseURL: '/myBase',
});
apiAxios.interceptors.request.use(
async (req) => {
// HERE i am trying to get token from cookies
// and also HERE if token is expired i am trying to refresh token
config.headers.Authorization = token;
req.headers['Content-type'] = 'application/x-www-form-urlencoded';
return req;
},
(error) => {
return Promise.reject(error);
},
);
export default apiAxios;
I am stuck here because i cant find token during apiAxios.interceptors.request.use...
Did you know what i am doing wrong, and am i on a correct way to handle this behavior ?
To allow sending server cookie to every subsequent request, you need to set withCredentials to true. here is the code.
const apiAxios = axios.create({
baseURL: '/myBase',
withCredentials: true,
});
Nilesh's answer is right if your API is able to authorize requests based on cookies. Also it needs the API to be in the same domain as your frontend app. If you need to send tokens to the API (the one which is in the cookie), then you will need a small backend component often called BFF or Token Handler. It can extract the token from the cookie and put in an Authorization header.
At Curity we've created a sample implementation of such a Token Handler, of which you can inspire: https://github.com/curityio/kong-bff-plugin/ You can also have a look at an overview article of the Token Handler pattern.

Random "User does not have sufficient permissions for this profile." error from Google Analytics API v3

I am receiving this error randomly when I am trying to send a request to Google Analytics API v3:
"User does not have sufficient permissions for this profile."
From every 8-10 times that I try a same request (same parameters, authentication, etc.), I receive this error only once and the other times I receive the correct response in the other times. The other strange part is that we are handling many clients and I only have seen this error for only handful of our clients.
For more background, we are using googleapis NPM package to send our Google Analytics API requests.
This is parameters that I am sending to the API:
{
params: {
auth: OAuth2Client {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
transporter: DefaultTransporter {},
credentials: [Object],
eagerRefreshThresholdMillis: 300000,
forceRefreshOnFailure: false,
certificateCache: {},
certificateExpiry: null,
certificateCacheFormat: 'PEM',
refreshTokenPromises: Map {},
_clientId: 'XXXXX,
_clientSecret: 'XXXX',
redirectUri: 'postmessage'
},
ids: 'ga:XXXX',
metrics: 'ga:sessions,ga:bounces,ga:transactions,ga:transactionRevenue,ga:goalCompletionsAll',
dimensions: 'ga:date',
'start-date': '2021-10-01',
'end-date': '2021-10-20',
samplingLevel: 'HIGHER_PRECISION',
quotaUser: 'XXX'
}
}
new Promise((resolve, reject) => {
return google
.analytics({ version: "v3"})
.data.ga.get(params, (error, { data: response } = {}) => {
if (error) {
return reject(new Error(`Google API sent the following error: ${error}`));
}
return resolve(response);
});
})
Authentication:
const OAuth2 = google.auth.OAuth2;
const oauth2Client = new OAuth2(process.env.GOOGLE_CLIENT_ID, process.env.GOOGLE_CLIENT_SECRET, "postmessage");
oauth2Client.setCredentials(tokens);
await oauth2Client.getRequestHeaders().catch((error) => {
throw error;
});
And then passing oauth2Client in the params as auth.
I resolved the issue. In my case I was using the same object of oauth2Client for multiple API requests but was calling these lines before each request:
oauth2Client.setCredentials(tokens);
await oauth2Client.getRequestHeaders();
This could potentially change the token that I was passing in the request parameters, params, before it was being sent.
So in other words if you are sending multiple requests to the API at the same time, it is better to generate the token once and use the same token for all those requests.

The generated token with vdomah JWT plugin in october cms is not accepted by the route with flutter

Hello i'm using flutter and i built an api with october cms.
I used the plugin by vdomah for the JWT Authentication, i think i followed the README.md but when i try to send the token to the api, i think is not accepted, the code:
the route:
Route::post('storephoto', function (Work $Work, Request $request) {
...
$Work->save();
})->middleware('Tymon\JWTAuth\Middleware\GetUserFromToken');
the flutter side:
upload(String fileName) {
http.post(AppUrl.baseURL + "/storephoto",
headers: {
'Authorization': 'Bearer $token'
},
body: {
"name": workNameController.text,
"images": fileName,
"description": descriptionController.text
}).then((result) {
setStatus(result.statusCode == 200 ? result.body : errMessage);
if(result.statusCode == 200) {
Navigator.push(context,
MaterialPageRoute(
builder: (context) => MainScreen()));
};
}).catchError((error) {
setStatus(error);
});
}
I printed the token in this function, and it exists, but i can't see the error in console.
I tried to make a GET route and the api seems to work in the browser, the message:
{
"error": "token_not_provided"
}
Now i think the token generated is not signed, or not recognized, how i can do?
Thanks in advance.
Once I faced the same issue, not sure there is some issue in the plugin, and doing the below change solved it.
plugins/vdomah/jwtauth/Plugin.php in this file do below change.
if you have any doubts please comment.
and can you use middleware like this
Route::group(['middleware' =>
['\Tymon\JWTAuth\Middleware\GetUserFromToken']], function() {
Route::post('storephoto', function (Request $request) {
//..code
});
});
as if I do like this its working

Not getting refresh_token when authenticating with paypal API

Node.js
Using paypal sandbox env
const PAYPAL_BASE_URL = "https://api.sandbox.paypal.com";
const PAYPAL_TOKEN_URL = `${PAYPAL_BASE_URL}/v1/oauth2/token`;
const tokenOptions = {
method: "post",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Access-Control-Allow-Credentials": true,
},
data: qs.stringify({ grant_type: "client_credentials" }),
auth: {
username: `${CLIENT_ID}`,
password: `${CLIENT_SECRET}`,
},
url: `${PAYPAL_TOKEN_URL}`,
};
async function getToken() {
return await axios(tokenOptions)
.then((res) => {
console.log(res.data.access_token);
console.log(res.data.expires_in);
console.log(res.data);
return res.data;
})
.catch((err) => {
console.log(err);
});
}
Response
"scope": "https://uri.paypal.com/services/invoicing https://uri.paypal.com/services/disputes/read-buyer https://uri.paypal.com/services/payments/realtimepayment https://uri.paypal.com/services/disputes/update-seller https://uri.paypal.com/services/payments/payment/authcapture openid https://uri.paypal.com/services/disputes/read-seller https://uri.paypal.com/services/payments/refund https://api.paypal.com/v1/vault/credit-card https://api.paypal.com/v1/payments/.* https://uri.paypal.com/payments/payouts https://api.paypal.com/v1/vault/credit-card/.* https://uri.paypal.com/services/subscriptions https://uri.paypal.com/services/applications/webhooks",
"access_token": "xxxxxxxx",
"token_type": "Bearer",
"app_id": "xxxx",
"expires_in": 32346,
"nonce": "2020-11-07T20:09:09Zmc3xM34owS0WsAI5rHVx2eOJb80xJ06Z6tFQx6LT_i0"
As you can see I am not getting the refresh_token. Reading the documentation I wanted to use the refresh token to get a new access_token when the expire time is getting close.
Should I not be getting a refresh_token here?
A client credentials request using a clientid/secret does not give a refresh_token.
Just repeat the same request when needed.
#Preston PHX
Adding a comment here as the comments does not allow that many characters.
Can I do something to get a refresh_token?
Problems I have is that I am using node as a proxy with http-proxy-middleware.
app.use("/", PROXY_TO_PAYPAL);
On app startup I authenticate and store the token in a variable that will expire.
console.log(`Starting proxy at ${HOST}:${PORT}`);
console.log(`PAYPAL_TOKEN_URL: ${PAYPAL_TOKEN_URL}`);
// set the token on startup
getToken().then((data) => {
token = data.access_token;
console.log(`expires_in ${parseInt(data.expires_in)} seconds`);
const timeoutDate = getTimeoutDate(parseInt(data.expires_in) * 1000);
tokenTimeOut = timeoutDate.getUTCMilliseconds();
console.log(`Token times out at ${timeoutDate.toUTCString()}`);
});
});
I need to update the token BEFORE it expires, otherwise I risk that a proxy request will fail as it could potentially use an expired token.
I created a scheduler that will watch the when the token is getting close to expire and will renew it (call the authentication again), like say 15 min before.
async function getToken() {
return await axios(tokenOptions)
.then((res) => {
console.log(res.data.access_token);
console.log(res.data.expires_in);
console.log(res.data);
return res.data;
})
.catch((err) => {
console.log(err);
});
}
cron.schedule("* * * * *", function () {
console.log("running a task every minute");
// refresh token
if (tokenTimeOut - new Date().getUTCMilliseconds() < 900*1000) {
getToken().then((data) => {
token = data.access_token;
const timeoutDate = getTimeoutDate(parseInt(data.expires_in) * 1000);
tokenTimeOut = timeoutDate.getUTCMilliseconds();
console.log(`Token times out at ${timeoutDate.toUTCString()}`);
});
}
});
I am adding the Bearer header on each request bore it is proxied
const middlewareOptions = {
target: `${PAYPAL_BASE_URL}`, // target host
changeOrigin: true,
onProxyReq(proxyReq, req, res) {
if (!token) {
getToken().then((data) => {
token = data.access_token;
tokenTimeOut = data.expires_in;
});
}
proxyReq.setHeader("Authorization", `Bearer ${token}`);
},
};
I might get the same token again until I am closer to the expire date (I think) - which could work. Eventually I would get a new token and a new expire time.
I am confused about the documentation. Here they talk about the refresh_token https://developer.paypal.com/docs/connect-with-paypal/integrate/#6-get-access-token
But here there are not refresh_token
https://developer.paypal.com/docs/api/get-an-access-token-curl/
What I wanted to do is when I am close to the expire time I would use the refresh_token to get a new token.

Flask_SocketIO Not emitting custom events

I have a Flask_SocketIO app that supposed to implement a chat groups system.
The client thats interacting with it is a flutter app.
I wrote a test to see if the socketio events are working. it worked once, but than stopped.
the server is getting the client's emits but not emitting back to the client.
also, the connection related evets (connect, disconnect, error) seems to be fully working. the client's callbacks on these events are called.
My flutter test client:
void main() async {
setupLocator();
final api = locator<Api>();
final socketService = locator<SocketService>();
Message msg = Message(
msgId: null,
content: "Hello!",
senderId: 1,
senderName: 'tair',
sendtime: DateTime.now().toString(),
groupId: 1);
runApp(
MaterialApp(
home: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text("Disconnect"),
onPressed: () {
socketService.leave(1, 1);
}),
RaisedButton(
child: Text("Send"),
onPressed: () {
socketService.sendMessage(msg);
},
),
RaisedButton(
child: Text("Connect"),
onPressed: () {
socketService.connect(1, 1, (data) {
print('Data!');
print(data);
});
},
),
],
),
),
),
);
SharedPreferences.setMockInitialValues({});
await api.login('tair', '1234');
await socketService.getToken();
socketService.connect(1, 1, (data) {
print('Data!');
print(data);
});
Api: A class that's interacting with rest api. not related
SocketService: A class that's emitting and listening to events. im giving the connect() method
parameters in order to join a socketio room on the server side
locator: Dependency injecttion using pub package get_it. also not related
Here's the events on my Server:
#sock.on('join')
def join_group_room(data):
print(data)
token = data['token']
if token in user_token.keys():
group = Group.query.filter_by(id=int(data['groupId'])).first()
if group.temp_participants is None:
group.temp_participants = data['userId'] + ','
else:
group.temp_participants += data['userId'] + ','
db.session.commit()
join_room(data['groupId'])
#print(rooms())
else:
emit('error', 'Invalid token')
#sock.on('message')
def message_room(data):
print(data)
token = data['token']
if token in user_token.keys():
message = Message(content=data['message'], groupid=int(data['groupId']), username=user_token[token],
datetime=data['datetime'])
db.session.add(message)
db.session.commit()
participants = Group.query.filter_by(id=message.groupid).first().participants.split(",")
temp_participants = Group.query.filter_by(id=message.groupid).first().temp_participants.split(",")
for participant in participants:
if participant not in temp_participants:
pushbots.push_batch(platform=pushbots.PLATFORM_ANDROID,
alias=participant,
msg='A new message arrived', payload={'data': {'message': message.content,
'messageId': message.id,
'username': user_token[
token],
'datetime': message.datetime,
'groupId': message.groupid,
'userId': User.query.filter_by(
username=user_token[
token]).first().id}})
print("Emitting")
emit('message', {'message': message.content, 'messageId': message.id,
'username': user_token[token], 'datetime': message.datetime,
'groupId': message.groupid,
'userId': User.query.filter_by(username=user_token[token]).first().id},
room=message.groupid)
sock.sleep(0)
else:
emit('error', 'Invalid token')
#sock.on('leave')
def leave_group_room(data):
print(data)
token = data['token']
if token in user_token.keys():
group = Group.query.filter_by(id=int(data['groupId'])).first()
group.temp_participants = str(group.temp_participants.split(",").remove(data['userId'])).strip('[]')
db.session.commit()
leave_room(data['groupId'])
emit('error', 'Invalid token')
Im using eventlet as async_mode for the socketio app. i looked up online for solutions and many people said i should add the following line to the main script:
import eventlet
eventlet.monkey_patch()
Also, according to my partner on this project, the events are working fine on his machine
for further explaination, here is the link to my git repo, so you can watch the whole code: My git repo (its on integration/ClientServer branch)
Thanks for helping!
Apperantly, room names can be only strings, but the emit function wont throw an error if youll pass an int as the room parameter.