I am using following code for creating the token on UI:
const { token, error } = await this.stripeInstance.createToken(this.cardNumber, {
name, address_zip, address_country
});
I am able to fill the form with wrong CVV code, but token successfully created, and fails right after backend using it.
Is there any way to validate the card before creating a token?
The response, I am receiving from stripe contains:
address_line1_check: null
address_zip_check: "unchecked"
cvc_check: "unchecked"
Related
In example project provided by Microsoft here which uses Authorization code flow the acquireTokenByCode method does not return refresh tokens.
From #azure/msal-node here refresh token is not mentioned.
Result returned from the authority's token endpoint.
uniqueId - oid or sub claim from ID token
tenantId - tid claim from ID token
scopes - Scopes that are validated for the respective token
account - An account object representation of the currently signed-in user
idToken - Id token received as part of the response
idTokenClaims - MSAL-relevant ID token claims
accessToken - Access token received as part of the response
fromCache - Boolean denoting whether token came from cache
expiresOn - Javascript Date object representing relative expiration of access token
extExpiresOn - Javascript Date object representing extended relative expiration of access token in case of server outage
state - Value passed in by user in request
familyId - Family ID identifier, usually only used for refresh tokens
please ensure your MSAL authorization code request includes the offline_access scope.
You could use MSAL.js to get token in this case, there is acquireTokenSilent method, it can perform silent renewal of tokens, which means you are no need to get the refresh token by yourself.
Popup
var request = {
scopes: ["Mail.Read"]
};
msalInstance.acquireTokenSilent(request).then(tokenResponse => {
// Do something with the tokenResponse
}).catch(async (error) => {
if (error instanceof InteractionRequiredAuthError) {
// fallback to interaction when silent call fails
return myMSALObj.acquireTokenPopup(request);
}
}).catch(error => {
handleError(error);
});
Redirect
var request = {
scopes: ["Mail.Read"]
};
msalInstance.acquireTokenSilent(request).then(tokenResponse => {
// Do something with the tokenResponse
}).catch(error => {
if (error instanceof InteractionRequiredAuthError) {
// fallback to interaction when silent call fails
return myMSALObj.acquireTokenRedirect(request)
}
});
It's designed to not return the refresh token if you are using #azure/msal-node.
As they stated in the discussion, the refresh token is handled background, inside the library itself for better security, which I also disagree with.
However, if you insist to have the token, you can manually call the API to the AzureAD endpoint.
I have a bot in NodeJS connected to Google Chat using HTTPs endpoints. I am using express to receive requests. I need to verify that all requests come from Google, and want to do this using the Bearer Token that Google Sends with requests.
My problem is that I am struggling to find a way to verify the tokens.
I have captured the token and tried a GET reuqes to https://oauth2.googleapis.com/tokeninfo?id_token=ey... (where ey... is the token start).
Which returns:
"error": "invalid_token",
"error_description": "Invalid Value"
}
I have tried what Google recommends:
var token = req.headers.authorization.split(/[ ]+/);
client.verifyIdToken({
idToken: token[1],
audience: JSON.parse(process.env.valid_client_ids)
}).then((ticket) => {
gchatHandler.handleGChat(req.body, res);
}).catch(console.error);
And get the following error:
Error: No pem found for envelope: {"alg":"RS256","kid":"d...1","typ":"JWT"}
Any idea where I should head from here?
Edit: https://www.googleapis.com/service_accounts/v1/metadata/x509/chat#system.gserviceaccount.com found this, investigating how to use it. The kid matches the one I get.
Worked it out, eventually.
You need to hit: https://www.googleapis.com/service_accounts/v1/metadata/x509/chat#system.gserviceaccount.com to get a JSON file containing the keys linked to their KIDs.
Then when a request arrives, use jsonwebtoken (NPM) to decode the token and extract the KID from the header.
Use the KID to find the matching public key in the response from the website above, then use the verify function to make sure the token matches the public key.
You also need to pass the audience and issuer options to verify, to validate that it is your particular service account hitting the bot.
The solution above maybe the correct for Google Chat, but in my experience Google services (e.g. Google Tasks) use OIDC tokens, which can be validated with verifyIdToken function.
Adding my solution here, since your question/answer was the closest thing I was able to find to my problem
So, In case if you need to sign a request from your own code
on client, send requests with OIDC token
import {URL} from 'url';
import {GoogleAuth} from 'google-auth-library';
// will use default auth or GOOGLE_APPLICATION_CREDENTIALS path to SA file
// you must validate email of this identity on the server!
const auth = new GoogleAuth({});
export const request = async ({url, ...options}) => {
const targetAudience = new URL(url as string).origin;
const client = await auth.getIdTokenClient(targetAudience);
return await client.request({...options, url});
};
await request({ url: 'https://my-domain.com/endpoint1', method: 'POST', data: {} })
on the server, validate OIDC (Id token)
const auth = new OAuth2Client();
const audience = 'https://my-domain.com';
// to validate
const token = req.headers.authorization.split(/[ ]+/)[1];
const ticket = await auth.verifyIdToken({idToken: token, audience });
if (ticket.getPayload().email !== SA_EMAIL) {
throw new Error('request was signed with different SA');
}
// all good
Read more about Google OpenID Connect Tokens
We use Firebase for Authenticating our login process, at the backend we have a Rest API implementation in order to verify the token that is being passed.
I have modified the .json file and verified yet another time too in my code base. I have extracted the entire process of generating the token from the UID and this is how this looks:
public void initialization(){
try {
FileInputStream refreshToken = new FileInputStream("c02955c26b.json");
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(refreshToken))
.setDatabaseUrl("https://164d0.firebaseio.com")
.build();
String uid = "Lp14BXL3xPVW7K8VZX28omynbWx1";
FirebaseAuth firebaseAuth= FirebaseAuth.getInstance(FirebaseApp.initializeApp(options));
System.out.println(" "+firebaseAuth); --> I see this on the console
String customToken = firebaseAuth.createCustomToken(uid);
System.out.println(" "+customToken);
FirebaseToken decodedToken = firebaseAuth.verifyIdToken(customToken);
String uidTranspose = decodedToken.getUid();
System.out.println(" the UID sent is"+uid+"Obtained after transpose is"+uidTranspose);
System.out.println(" the UID captured is this "+uid);
}
catch(Error e){
System.out.println(" "+e.getLocalizedMessage());
e.printStackTrace();
}
finally{
System.out.println("Finally comes here ");
}
}
Somewhere on hitting the token creation, the control flows directly to the finally block; without logging an error or an exception.
I am not sure if I am missing anything here.
Edit 1: Edited to add the complete code.
Edit 2: I am able to see the Token being created. but I am unable to verify the same; because it says this is a custom token and not the Id Token. I am not sure if I can access the Id Token or if there is a way to verify the custom token.
You cannot call verifyIdToken() with a custom token. See Verifying firebase custom token to get token ID fails when using jsonwebtoken
I have managed to make Account Linking on Android using actions on google sdk and Dialogflow but can't make it work using the new Dialogflow V2 webhook.
It does ask permission to link account and the account linking does happen but I cannot access the user data like given_name, email, etc.
I have done everything required including creating the intent with actions_intent_SIGN_IN which gets called as expected except that I don't get the information that I should.
This is the code that is called to create sign in
function googleSignIn() {
console.log('In googleSignIn')
const conv = agent.conv()
// conv.ask(new SignIn('To get your account details'))
// conv.ask('Hello')
var payload = {
"expectUserResponse": true,
"systemIntent": {
"intent": "actions.intent.SIGN_IN",
"data": {}
}
}
// agent.add(payload)
console.log('add googleSignIn payload')
agent.add('Placeholder_google_payload')
agent.add(new Payload(agent.ACTIONS_ON_GOOGLE, payload))
}
This gets called when the intent is fired by Actions on Google
function getSignIn(agent) {
console.log('In function getSignin: ')
const conv = agent.conv()
console.log('conv parts: ', JSON.stringify(conv.user))
agent.add('User profile:', conv.user);
// console.log('conv access token: ', JSON.stringify(conv.user.access.token))
}
With help from Prisoner I managed to solve the problem. You basically just get the token which has to be decoded. This is the relevant code.
var jwt = require('jsonwebtoken'); // use npm i jsonwebtoken to get
const profile = jwt.decode(conv.user.profile.token);
console.log('Profile: ', profile);
// you can then get the elements from the profile (instead of payload)
// e.g.
console.log('Name: ', profile.name);
Once the user has signed in once using Google Sign In for Assistant, all further requests will contain an id token.
If you are using the actions-on-google library, the token will be in the conv object as conv.user.profile.id and the profile information itself (the "payload" of the id token) will be in conv.user.profile.payload.
If you're using the dialogflow-fulfillment library, you can get the conv object from agent.getConv().
If you're using the multivocal library, the user profile is stored in the environment under User/Profile with the id token available under User/IdentityToken and User/IsAuthenticated will be set to true.
This will be sent to you for this session, and any future session as long as the user doesn't disconnect your Action from their account.
Stripe supports two-step payment flow for authorizing and capturing money on cards. For that we have to send a capture = false parameter.
My question is how do i send this parameter in javascript api??
var args = {
number: jQuery('#AccountNumber').val(),
exp_month: jQuery('#ExpirationMonth').val(),
exp_year: jQuery('#ExpirationYear').val(),
address_line1: jQuery('#baddress1').val(),
address_line2: jQuery('#baddress2').val(),
address_city: jQuery('#bcity').val(),
address_state: jQuery('#bstate').val(),
address_zip: jQuery('#bzipcode').val(),
address_country: jQuery('#bcountry').val()
};
//create token
Stripe.createToken(args, stripeResponseHandler);
A typical payment flow with Stripe can be divided in two steps:
Client-side, in your frontend (HTML + Javascript) code, you collect the customer's payment information using Stripe's prebuilt Checkout form, or your own custom form with the Stripe.js library. This will return a token that you then send to your server.
Server-side, in your backend code (in PHP, Python, Ruby, or whichever server-side programming language you prefer), you use the token in a charge creation request to actually charge the card.
If you want to use the "auth & capture" flow, you need to pass the capture=false parameter in the charge creation request, i.e. in your server-side code, not in the token creation step.
Replace Stripe.createToken(args, stripeResponseHandler); with
Stripe.card.createToken(args, stripeResponseHandler);
Now your stripeResponseHandler is a Javascript function that is executed once a response is received from Stripe's servers after capturing the credit card details. So you would need some sort of code to process the response:
function stripeResponseHandler(status, response) {
// Grab the form:
var $form = $('#payment-form');
if (response.error) { // Problem!
// Show the errors on the form
$form.find('.payment-errors').text(response.error.message);
$form.find('button').prop('disabled', false); // Re-enable submission
} else { // Token was created!
// Get the token ID:
var token = response.id;
// Insert the token into the form so it gets submitted to the server:
$form.append($('<input type="hidden" name="stripeToken" />').val(token));
// Submit the form:
$form.get(0).submit();
}
}
For more information: https://stripe.com/docs/stripe.js#collecting-card-details