Authorize to a 3rd party service within Postman request - api

Want to create request in Postman to cover authorization to a 3rd party within request. In application it works this way:
Client clicks the button
Application checks whether there is a token, if not it returns link to the 3rd party service to authorize there
Client follows the link, inputs credentials, submits form
Service redirects client back to the application with authorization code as a query parameter.
Client pushes another button to receive token by the authorization code.
So, is there a way to proceed this scenario within the Postman, not to copy link from response and pasting it to browser in order to complete authorization?
Tried to make request from Test script tab like:
var jsonData = JSON.parse(responseBody);
console.log(jsonData.data)
if (jsonData.data) {
pm.sendRequest(jsonData.data, function (err, response) {
console.log(response);
return response;
});
}
But that was not actually useful

There is a way to get token before request.
You can use Pre-request Script bookmark.
Write JS code to get token and save it to variable (collection / environment).
In specific request open Authorization bookmark and call your variable.
For Bearer:
My Pre-Request Script for example:
let collUsername = pm.variables.get("username");
let collPassword = pm.variables.get("password");
let collClient_id = pm.variables.get("client_id");
let collClient_secret = pm.variables.get("client_secret");
const postRequest = {
url: pm.variables.get("url"),
method: 'POST',
header: {
'Accept': '*/*',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: {
mode: 'urlencoded',
urlencoded : [
{ key: 'username', value: collUsername},
{ key: 'password', value: collPassword},
{ key: 'grant_type', value: 'password'},
{ key: 'client_id', value: collClient_id},
{ key: 'client_secret', value: collClient_secret},
{ key: 'user_type', value: 'System'}
]
}
};
pm.sendRequest(postRequest, (error, response) => {
console.log(error ? error : response.json());
let jsonRes = response.json();
pm.collectionVariables.set("token", jsonRes.access_token);
});
I don't know your authentication method so your script can be different.
If you want to refresh only expired token you can add variable with date and check if appropriate time has passed to get new token.
Edit: Scripts written in Tests are executed after getting response so not proper place for your case.

Related

Unexpected behaviour of payment_intent api with GET and POST method

I am using the payment_intent API to generate payment intent for payment sheet initialization.
As per the document, payment_intent is the POST method. Showing different errors in android and iOS.
https://stripe.com/docs/api/payment_intents/create
Note:- It's working in postman not working on mobile.
Case 1 Android
It is not working with the POST method. It worked with the GET method this is weird.
Case 2 iOS
It is not working with the GET and POST methods both.
With POST received the following error
_response": "{
\"error\": {
\"code\": \"parameter_missing\",
\"doc_url\": \"https://stripe.com/docs/error-codes/parameter-missing\",
\"message\": \"Missing required param: amount.\",
\"param\": \"amount\",
\"type\": \"invalid_request_error\"
}
}
With GET method received the following error
"_response":"resource exceeds maximum size"
End Point URL:-
let data = JSON.stringify({
customer: customerId,
currency: 'inr',
amount: 1000,
'automatic_payment_methods[enabled]': 'true',
});
let config = {
method: 'GET',
url: 'https://api.stripe.com/v1/payment_intents',
headers: {
Authorization:
'Bearer sk_test_DmXI7Jw1PnJAWYps3iCpvKkttIGX00pPfGLTjj',
'Content-Type': 'application/x-www-form-urlencoded',
},
data: data,
};
axios(config)
.then(function (response) {
console.info(JSON.stringify(response));
})
.catch(function (error) {
console.error('-----', error.response);
});
Following this document
https://stripe.com/docs/payments/accept-a-payment?platform=react-native&ui=payment-sheet#react-native-flowcontroller
https://stripe.com/docs/api/payment_intents/create
Added snack URL to reproduce the issue.
https://snack.expo.dev/#vishaldhanotiya/stripe-payment-intent
Error Log
To clarify a few things:
1/ You shared your (test mode) secret key in your code snippet, please delete that and roll your API keys (https://stripe.com/docs/keys#keeping-your-keys-safe).
2/ Your iOS/Android apps should not be making requests to Stripe's APIs directly with your secret API key, as that means you are bundling your secret key with your apps which means anyone running your app has access to your secret key.
Instead, you need to make requests from your iOS app to your server and your server should use Stripe's server-side libraries to make requests to Stripe's APIs. Your iOS/Android apps can only make requests with your publishable key.
3/ The PaymentIntent endpoint supports both POST and GET. You can create a PaymentIntent by POSTing to the /v1/payment_intents endpoint, you retrieve a single PaymentIntent with a GET to the /v1/payment_intents/:id endpoint and you list PaymentIntents with a GET to the /v1/payment_intents endpoint.
4/ The error in your POST request shows "Missing required param: amount." so you need to debug your code to make sure the amount parameter is getting through. You can use Stripe's Dashboard Logs page https://dashboard.stripe.com/test/logs to debug what parameters your code is sending to Stripe's API.
Finally, I found a solution. The issue occurred because I am send parameters without encoding.
I found a solution from this link
https://stackoverflow.com/a/58254052/9158543.
let config = {
method: 'post',
url: 'https://api.stripe.com/v1/payment_intents',
headers: {
Authorization:
'Bearer sk_test_51J3PfGLTjj',
'Content-Type': 'application/x-www-form-urlencoded'
}
};
let paymentDetail = {
customer: 'cus_MSiYLjtdaJPiCW',
currency: 'USD',
amount: 100,
'automatic_payment_methods[enabled]': true
};
let formBody: any = [];
for (let property in paymentDetail) {
let encodedKey = encodeURIComponent(property);
let encodedValue = encodeURIComponent(paymentDetail[property]);
formBody.push(encodedKey + '=' + encodedValue);
}
formBody = formBody.join('&');
const result = await axios
.post('https://api.stripe.com/v1/payment_intents', formBody, {
headers: config.headers
})
.then(function (response) {
console.info(JSON.stringify(response));
})
.catch(function (error) {
console.error('-----', error.response);
});

Problems to get a refresh token using vue, nuxt and keycloak

I'm doing a project with vue, nuxt and keycloak as server for token, axios as http client and #nuxtjs/auth-next module for keycloak access.
I'm using a public client so I don't have a secret key which is the most recommended.
The part of getting the token and talking to the backend is working.
But as it is a public client it has no refresh token.
Searching the internet, a recommendation would be to post from time to time to the keycloak /token endpoint, passing the current token, to fetch a new token.
To perform this post, it doesn't work to pass json, having to pass application/x-www-form-urlencoded.
But it generates an error saying that the parameter was not passed.
On the internet they recommended passing it as url string, but then it generates an error on the keycloak server, as a parameter that is too long, because of the current token that is passed.
Below is the code used to try to fetch a new token.
This code is being called on a test-only button.
If anyone can help, I appreciate it.
const token = this.$auth.strategy.token.get()
const header = {
"Content-Type": "application/x-www-form-urlencoded"
}
const body = {
grant_type: "authorization_code",
client_id: "projeto-ui",
code: token
}
this.$axios ( {
url: process.env.tokenUrl,
method: 'post',
data: body,
headers: header
} )
.then( (res) => {
console.log(res);
})
.catch((error) => {
console.log(error);
} );
Good afternoon people.
Below is the solution to the problem:
On the keycloak server:
it was necessary to put false the part of the implicit flow.
it was necessary to add web-origins: http://localhost:3000, to allow CORS origins.
In nuxt.config.js it was necessary to modify the configuration, as below:
auth: {
strategies: {
keycloak: {
scheme: 'oauth2',
...
responseType: 'code',
grantType: 'authorization_code',
codeChallengeMethod: 'S256'
}
}
}

K6 - Authentication - Get Auth Token

I have a mocha javascript file in which I have require function to login to the application in headless browser mode, login using the crendentials and return the jwt authentication.
I want to call this script through K6. But as I understand, calling node module java script from K6 is not possible?
Is there an alternative to this?
I have also just started implementing k6 and had same step to do ;)
Here is how I have done it.
you need to know how to authenticate to the API you want to use. I assume we have it, as you wrote you want to use node modules.
second, use appropriate method to communicate with API
next, catch token and append it to next requests headers
finally, test API with requests you want
I found code snippets on web page with k6 samples for APIs.
I have shorten a bit, sample code and end up with:
import {
describe
} from 'https://jslib.k6.io/functional/0.0.3/index.js';
import {
Httpx,
Request,
Get,
Post
} from 'https://jslib.k6.io/httpx/0.0.2/index.js';
import {
randomIntBetween,
randomItem
} from "https://jslib.k6.io/k6-utils/1.1.0/index.js";
export let options = {
thresholds: {
checks: [{
threshold: 'rate == 1.00',
abortOnFail: true
}],
},
vus: 2,
iterations: 2
};
//defining auth credentials
const CLIENT_ID = 'CLIENT_ID';
const CLIENT_SECRET = 'CLIENT_SECRET';
let session = new Httpx({
baseURL: 'https://url.to.api.com'
});
export default function testSuite() {
describe(`01. Authenticate the client for next operations`, (t) => {
let resp = session.post(`/path/to/auth/method`, {
//this sections relays on your api requirements, in short what is mandatory to be authenticated
grant_type: GRANT_TYPE,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
});
//printing out response body/status/access_token - for debug
// console.log(resp.body);
// console.log(resp.status);
// console.log(resp.json('access_token'));
//defining checks
t.expect(resp.status).as("Auth status").toBeBetween(200, 204)
.and(resp).toHaveValidJson()
.and(resp.json('access_token')).as("Auth token").toBeTruthy();
let authToken = resp.json('access_token');
// set the authorization header on the session for the subsequent requests.
session.addHeader('Authorization', `Bearer ${authToken}`);
})
describe('02. use other API method, but with authentication token in header ', (t) => {
let response = session.post(`/path/to/some/other/post/method`, {
"Cache-Control": "no-cache",
"SomeRequieredAttribute":"AttributeValue"
});
t.expect(response.status).as("response status").toBeBetween(200, 204)
.and(response).toHaveValidJson();
})
}

Accessing the response from one GET request within another

I'm working with Vue to interact with an external API on a Drupal website, but in order to do so dynamically per Drupal user, I need to get a token from Drupal first. To do so, I'm trying to do two GET requests. The first gets me a bearer token out of Drupal, and the second uses it to authenticate the third-party API request.
Below is what I'm trying – I'm able to get the token successfully in the first request's response, but not when I try to use it in the header of my second request. If I try hardcoding the token that I see in the console log, it does work, so I know none of that is the issue. It's just that this.jwt['data']['token'] in the second request's headers seems to not pull back the token.
What do I need to adjust in order to access the token from the first response as part of the headers of my second request?
created() {
axios
.get('/jwt/token')
.then(response => {
this.jwt = response
console.log(this.jwt['data']['token']) // this does show what I want to access later
})
},
mounted() {
axios
.get('/comment/doc/' + this.id, {
headers: { Authorization: "Bearer " + this.jwt['data']['token'] } // ...but this doesn't work
})
.then(response => {
this.comments = response
})
},
It's likely the response to the token request has not finished by the time the component mounts, at which point this.jwt is not yet assigned.
I would move the token request into the mounted hook, fetching comments only when the token request succeeds:
export default {
mounted() {
axios
.get('/jwt/token')
.then(tokenResp => {
this.jwt = tokenResp
axios
.get('/comment/doc/' + this.id, {
headers: { Authorization: 'Bearer ' + this.jwt['data']['token'] }
})
.then(commentsResp => {
this.comments = commentsResp
})
})
}
}

graphql server email verify example

I'm starting to work on an express API using graphql with apollo-server-express and graphql-tools. My register user process steps are:
User submit user name, email and password.
Server send an email to user by Mailgun with unique link generated by uuid.
User follow the link to verify the registration.
But I'm in struggle at how to bind the mutation in the resolver. See snippets:
server.js
const buildOptions = async (req, res, done) => {
const user = await authenticate(req, mongo.Users)
return {
schema,
context: {
dataloaders: buildDataloaders(mongo),
mongo,
user
},
}
done()
}
// JWT setting
app.use('/graphAPI',
jwt({
secret: JWT_SECRET,
credentialsRequired: false,
}),
graphqlExpress(buildOptions),
res => data => res.send(JSON.stringify(data))
)
Mutation on resolver
signupUser: async (root, data, {mongo: { Users }}) => {
// Check existed accounts,
// if account is not exist, assign new account
const existed = await Users.findOne({email: data.email})
if (!existed) {
// create a token for sending email
const registrationToken = {
token: uuid.v4(),
created_at: new Date(),
expireAfterSeconds: 3600000 * 6 // half day
}
const newUser = {
name: data.name,
email: data.email,
password: await bcrypt.hash(data.password, 10),
created_at: new Date(),
verification_token: registrationToken,
is_verified: false,
}
const response = await Users.insert(newUser)
// send and email to user
await verifyEmail(newUser)
return Object.assign({id: response.insertedIds[0]}, newUser)
}
// Throw error when account existed
const error = new Error('Email existed')
error.status = 409
throw error
},
// VERIFY USER
// Set verify to true (after user click on the link)
// Add user to mailist
verifiedUser: async (root, data, {mongo: { Users }}) => {
await Users.updateOne(
{ email: data.email },
{
set: {is_verified: true},
unset: {verification_token: {token: ''}}
}
)
},
route config
routes.get('/verify?:token', (req, res, next) => {
res.render('verified', {title: 'Success'})
})
the route config is where I stuck, because the object is passed to all resolvers via the context inside graphqlExpress
Any one help me out or suggest for me any articles related. Thanks so much.
You will need 3 graphql endpoints and 1 apollo http endpoint for proper workflow.
Optionally you can combine 3 graphql endpoints in one, but then it will be a one big function with a lot of different responsibilities.
1# graphql endpoint: changepass-request
expects email param
check if user with such email found in db:
generate code
save it in the local account node
send code to the user email with http link to confirm code:
http://yoursite.com/auth/verify?code=1234
return redirect_uri: http://yoursite.com/auth/confirm-code
for UI page with prompt for confirmation code
2# graphql endpoint: changepass-confirm
expects code param:
if user with such code found in db, return redirect_uri to UI page with prompt for new pass with confirmation code in params: http://yoursite.com/auth/change-pass?code=1234
3# graphql endpoint: changepass-complete
expects code and new pass:
hash new password
search in db for local account with such code
3a. if not found:
return error with redirect_uri to login page:
http://yoursite.com/auth?success=false&message="Confirmation code is not correct, try again."
3b. if found:
change password for new, return success status with redirect_uri to login page:
http://yoursite.com/auth?success=true&message="ok"
4# apollo HTTP endpoint: http://yoursite.com/auth/verify?code=1234
if no code provided:
redirect to UI registration page with error message in params:
http://yoursite.com/auth?success=false&message="Confirmation code is not correct, try again."
if code provided: search in db for local account with such code
1a. if user not found:
redirect to reg ui with err mess in params:
http://yoursite.com/auth?success=false&message="Confirmation code is not correct, try again."
1.b if user found:
redirect to ui page with new password prompt and attach new code to params
I didn't put any code above, so you can use this workflow in other auth scenarios.
It seems like rather than utilizing the verifiedUser endpoint, it would be simpler to just keep that logic inside the controller for the /verify route. Something like:
routes.get('/verify?:token', (req, res) => {
Users.updateOne(
{ verification_token: { token } },
{
$set: {is_verified: true},
$unset: {verification_token: {token: ''}}
},
(err, data) => {
const status = err ? 'Failure' : 'Success'
res.render('verified', {title: status})
}
)
})