I am using Amazon Cognito user pool and AdminCreateUser api to create a new user so that we don't allow users to sign themselves up. It works great but it seems that email verification step is being skipped so when making an api call, I needed to set email_verified attribute to true to make reset password flow to work.
Can I make email verification to happen before sending out an inviatation email?
const params = {
DesiredDeliveryMediums: ['EMAIL'],
UserAttributes: [
{
Name: 'email',
Value: email
},
{
Name: 'email_verified',
Value: 'True'
},
],
Username: email,
UserPoolId: userPoolId,
}
cognitoIdentityService.adminCreateUser(params, function(err, data) {
// ...
To prevent backend to send verification email, set MessageACtion="SUPPRESS"
response = client.admin_create_user(
UserPoolId='USER_POOL_ID',
Username='USERNAME',
TemporaryPassword='PASSWORD',
UserAttributes=[
{
'Name': 'email',
'Value': 'email#example.com'
},
{
'Name': 'email_verified',
'Value': 'true'
}
],
MessageAction='SUPPRESS'
)
Related
I am using Next Auth to authenticate through Azure Active Directory. I am successfully able to do so but the profile object does not contain some info I need.
I am trying to get the "user type" and "account status" properties.
Here's my code
providers: [
AzureADProvider({
clientId: process.env.AZURE_AD_CLIENT_ID,
clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
tenantId: process.env.AZURE_AD_TENANT_ID,
userinfo: {
url: 'https://graph.microsoft.com/v1.0/me/',
params: {
scope: 'https://graph.microsoft.com/user.read',
grant_type: 'authorization_code'
},
},
})
]
I don't know what to do after this point or even if this is what I should do. Any help is appreciated.
UPDATE:
Here's what I have after changing to what was suggested
providers: [
AzureADProvider({
clientId: process.env.AZURE_AD_CLIENT_ID,
clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
tenantId: process.env.AZURE_AD_TENANT_ID,
userinfo: {
url: 'https://graph.microsoft.com/v1.0/me?$select=accountEnabled,userType,displayName,givenName,objectId,email,surname',
params: {
scope: 'https://graph.microsoft.com/user.read',
grant_type: 'authorization_code',
},
},
profile(profile) {
return {
id: profile.objectId,
name: profile.displayName,
lastName: profile.surname,
firstName: profile.givenName,
email: profile.email,
userType: profile.userType,
accountStatus: profile.accountEnabled
};
}
})]
It seems like the profile data from the AzureADProvider is still being used because of the id token. I thought userinfo would overwrite it but it doesn't seem to work that way unless I am doing it wrong.
I tried to reproduce the same in my environment and got the results like below:
I created Azure AD Application and granted API permissions:
I generated the Access Token using Authorization Code Flow by using parameters like below:
GET https://login.microsoftonline.com/TenantId/oauth2/v2.0/token
client_id:ClientID
client_secret:ClientSecret
scope:https://graph.microsoft.com/user.read
grant_type:authorization_code
redirect_uri:RedirectUri
code:code
When I ran the same query as you, I dint get the userType and account status properties like below:
GET https://graph.microsoft.com/v1.0/me
Note that : By default only businessPhones, displayName, givenName, id, jobTitle, mail, mobilePhone, officeLocation, preferredLanguage, surname, userPrincipalName properties will be returned.
To get the additional user properties, make use of $select like below:
GET https://graph.microsoft.com/v1.0/me?$select=accountEnabled,userType
Modify the code like below:
providers: [
AzureADProvider({
clientId: process.env.AZURE_AD_CLIENT_ID,
clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
tenantId: process.env.AZURE_AD_TENANT_ID,
userinfo: {
url: 'https://graph.microsoft.com/v1.0/me?$select=accountEnabled,userType',
params: {
scope: 'https://graph.microsoft.com/user.read',
grant_type: 'authorization_code'
},
},
})
]
I found a solution. I had to use the request function inside userinfo and fetch the profile data.
AzureADProvider({
clientId: process.env.AZURE_AD_CLIENT_ID,
clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
tenantId: process.env.AZURE_AD_TENANT_ID,
userinfo: {
url: 'https://graph.microsoft.com/v1.0/me?$select=id,userPrincipalName,accountEnabled,userType,givenName,surname',
async request(context) {
const response = await axios.get('https://graph.microsoft.com/v1.0/me?$select=id,userPrincipalName,accountEnabled,userType,givenName,surname',
{
headers: {
'Authorization': `Bearer ${context.tokens.access_token}`
}
}
)
const newProfile = await response.data
return {
id: newProfile.id,
email: newProfile.userPrincipalName,
firstName: newProfile.givenName,
lastName: newProfile.surname,
userType: newProfile.userType,
accountStatus: newProfile.accountEnabled
};
}
},
profile(userinfo) {
console.log(userinfo)
return {
id: userinfo.id,
email: userinfo.userPrincipalName,
firstName: userinfo.givenName,
lastName: userinfo.surname,
userType: userinfo.userType,
accountStatus: userinfo.accountEnabled
};
}
}),
I got access token and I will pass access_token to userinfo endpoint it throwing an invalid token provided error How to fix this Issue. I tried to debug why this error is throwing we have validateAccessToken method(userinfo.js) in this method check the access_token is exist or not exist using this code await ctx.oidc.provider.AccessToken.find(accessTokenValue); when i print this result it's showing undefined
oidc_configuration.js
const oidc = new Provider('http://localhost:3000', {
clients: [
{
client_id: 'oidcCLIENT',
client_secret: '...',
grant_types: ['refresh_token', 'authorization_code'],
redirect_uris: ['http://sso-client.dev/providers/7/open_id', 'http://sso-client.dev/providers/8/open_id'],
}
],
interactions: {
url(ctx, interaction) { // eslint-disable-line no-unused-vars
return `/api/v1/open_id/interaction/${interaction.uid}`;
},
},
cookies: {
keys: ['some secret key', 'and also the old rotated away some time ago', 'and one more'],
},
claims: {
address: ['address'],
email: ['email', 'email_verified'],
phone: ['phone_number', 'phone_number_verified'],
profile: ['birthdate', 'family_name', 'gender', 'given_name', 'locale', 'middle_name', 'name',
'nickname', 'picture', 'preferred_username', 'profile', 'updated_at', 'website', 'zoneinfo'],
},
features: {
devInteractions: { enabled: false }, // defaults to true
deviceFlow: { enabled: true }, // defaults to false
revocation: { enabled: true }, // defaults to false
},
jwks: {
keys: [
{
d: 'VEZOsY07JTFzGTqv6cC2Y32vsfChind2I_TTuvV225_-0zrSej3XLRg8iE_u0-3GSgiGi4WImmTwmEgLo4Qp3uEcxCYbt4NMJC7fwT2i3dfRZjtZ4yJwFl0SIj8TgfQ8ptwZbFZUlcHGXZIr4nL8GXyQT0CK8wy4COfmymHrrUoyfZA154ql_OsoiupSUCRcKVvZj2JHL2KILsq_sh_l7g2dqAN8D7jYfJ58MkqlknBMa2-zi5I0-1JUOwztVNml_zGrp27UbEU60RqV3GHjoqwI6m01U7K0a8Q_SQAKYGqgepbAYOA-P4_TLl5KC4-WWBZu_rVfwgSENwWNEhw8oQ',
dp: 'E1Y-SN4bQqX7kP-bNgZ_gEv-pixJ5F_EGocHKfS56jtzRqQdTurrk4jIVpI-ZITA88lWAHxjD-OaoJUh9Jupd_lwD5Si80PyVxOMI2xaGQiF0lbKJfD38Sh8frRpgelZVaK_gm834B6SLfxKdNsP04DsJqGKktODF_fZeaGFPH0',
dq: 'F90JPxevQYOlAgEH0TUt1-3_hyxY6cfPRU2HQBaahyWrtCWpaOzenKZnvGFZdg-BuLVKjCchq3G_70OLE-XDP_ol0UTJmDTT-WyuJQdEMpt_WFF9yJGoeIu8yohfeLatU-67ukjghJ0s9CBzNE_LrGEV6Cup3FXywpSYZAV3iqc',
e: 'AQAB',
kty: 'RSA',
n: 'xwQ72P9z9OYshiQ-ntDYaPnnfwG6u9JAdLMZ5o0dmjlcyrvwQRdoFIKPnO65Q8mh6F_LDSxjxa2Yzo_wdjhbPZLjfUJXgCzm54cClXzT5twzo7lzoAfaJlkTsoZc2HFWqmcri0BuzmTFLZx2Q7wYBm0pXHmQKF0V-C1O6NWfd4mfBhbM-I1tHYSpAMgarSm22WDMDx-WWI7TEzy2QhaBVaENW9BKaKkJklocAZCxk18WhR0fckIGiWiSM5FcU1PY2jfGsTmX505Ub7P5Dz75Ygqrutd5tFrcqyPAtPTFDk8X1InxkkUwpP3nFU5o50DGhwQolGYKPGtQ-ZtmbOfcWQ',
p: '5wC6nY6Ev5FqcLPCqn9fC6R9KUuBej6NaAVOKW7GXiOJAq2WrileGKfMc9kIny20zW3uWkRLm-O-3Yzze1zFpxmqvsvCxZ5ERVZ6leiNXSu3tez71ZZwp0O9gys4knjrI-9w46l_vFuRtjL6XEeFfHEZFaNJpz-lcnb3w0okrbM',
q: '3I1qeEDslZFB8iNfpKAdWtz_Wzm6-jayT_V6aIvhvMj5mnU-Xpj75zLPQSGa9wunMlOoZW9w1wDO1FVuDhwzeOJaTm-Ds0MezeC4U6nVGyyDHb4CUA3ml2tzt4yLrqGYMT7XbADSvuWYADHw79OFjEi4T3s3tJymhaBvy1ulv8M',
qi: 'wSbXte9PcPtr788e713KHQ4waE26CzoXx-JNOgN0iqJMN6C4_XJEX-cSvCZDf4rh7xpXN6SGLVd5ibIyDJi7bbi5EQ5AXjazPbLBjRthcGXsIuZ3AtQyR0CEWNSdM7EyM5TRdyZQ9kftfz9nI03guW3iKKASETqX2vh0Z8XRjyU',
use: 'sig',
}, {
crv: 'P-256',
d: 'K9xfPv773dZR22TVUB80xouzdF7qCg5cWjPjkHyv7Ws',
kty: 'EC',
use: 'sig',
x: 'FWZ9rSkLt6Dx9E3pxLybhdM6xgR5obGsj5_pqmnz5J4',
y: '_n8G69C-A2Xl4xUW2lF0i8ZGZnk_KPYrhv4GbTGu5G4',
},
],
},
});
// Heroku has a proxy in front that terminates ssl, you should trust the proxy.
oidc.proxy = true;
const callback = oidc.callback();
How to fix this issue
You're running without a persistent adapter, meaning an in-memory one is used, are you possibly restarting your server after receiving the access token before calling the userinfo endpoint?
After completing the authentication, you will get access_token as well as id_token. I think you were using id_token in place of access_token which is why you are seeing that error
Instead use access_token then you can see the details
Can someone tell me if it's possible to create a userPool with MFA required, SMS MFA disabled but OTP MFA enabled.
On the AWS console, it doesn't seem to be an issue but for some reason through CDK, it isn't quite happy.
I have attempted to update an existing user pool as well as create one new.
new UserPool(this, 'foo-user-pool', {
userPoolName: 'foo',
selfSignUpEnabled: false,
passwordPolicy: {
minLength: 12,
requireDigits: true,
requireLowercase: true,
requireSymbols: true,
requireUppercase: true,
tempPasswordValidity: cdk.Duration.days(7)
},
accountRecovery: AccountRecovery.EMAIL_ONLY,
enableSmsRole: false,
mfa: Mfa.REQUIRED,
mfaSecondFactor: {
sms: false,
otp: true
},
signInAliases: {
email: true,
},
autoVerify: {
email: true,
},
})
Gives me the following error message and has been for some time now...
SMS configuration and Auto verification for phone_number are required when MFA is required/optional (Service: AWSCognitoIdentityProviderService; Status Code: 400; Error Code: InvalidParameterException; Request ID: bcc2143c-546a-439a-b7b5-6fcf3888cf9a; Proxy: null)
The link shows a PR that allows us to disabled the SMS role creation.
AWS CDK 1.77.0
I am using docusign (production account) to allow users to sign documents. I am trying to add data to textTabs that I create through the docusign dashboard. So say if I add a text box and call it nbShares, the below code does not populate the box. All the boxes I add in the dashboard such as signature, text, checkboxes etc are not shown in the generated link. I get no API errors either. I also tried to create customFields, and pass data to them as textTab - however this did not work either.
I think I may misunderstand the flow, I add all recipients and signers programatically - is that why I cant see the placeholders/buttons I add? I have also allowed collaboration in the fields I add, made them mandatory - yet they still do not appear.
Would really appreciate some help on this. This is my envelope definition - Im using the node sdk along with ts types.
const makeEnvelopeDefinition = async (
templateName: string,
user: User,
dealId?: string,
): Promise<EnvelopeDefinition> => {
const personToSign: Signer = {
email: user.email,
name: user.name,
roleName: 'Signer',
// Should this work?
tabs: {
textTabs: [
{ tabLabel: 'nbShares', value: '1000' },
],
},
clientUserId: DOCUSIGN_CLIENT_USER_ID,
recipientId: '1',
}
const compositeTemplate: CompositeTemplate = {
serverTemplates: [
{ sequence: '1', templateId: 'remote-template-id' },
],
inlineTemplates: [
{
sequence: '1',
recipients: {
signers: [personToSign],
certifiedDeliveries: [
{
email: 'someemail#something.com',
recipientId: '77',
name: 'Receipt of transaction',
},
{
email: user.email,
recipientId: '771',
name: user.name,
},
],
},
},
],
}
// create the envelope definition
const envelope: EnvelopeDefinition = {
emailSubject: 'Review signed document',
status: 'sent',
compositeTemplates: [compositeTemplate],
}
return envelope
}
For me the solution was changing my signer to this
const personToSign: Signer = {
email: user.email,
name: user.name,
clientUserId: await getDocusignConfig().DOCUSIGN_CLIENT_USER_ID,
recipientId: '1',
routingOrder: '1', // Was missing this
roleName: 'Signer', // Must match signer specified on docusign dashboard
tabs: {
textTabs: [
{
xPosition: '150',
yPosition: '200',
name: 'First Name',
tabLabel: 'name', // Must match the dataLabel name specified on docusign
value: 'Test',
},
],
},
}
And enabling this setting 'When an envelope is sent, write the initial value of the field for all recipients' in 'Signing Settings' on docusign.
I tried to run a script which creates a specific intent by using the Dialogflow API. The API is enabled already a couple of weeks.
After I called my script i received the following error:
Error: Dialogflow API has not been used in project usable-auth-library before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/dialogflow.googleapis.com/overview?project=usable-auth-library then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
at /Users/$USER"/Desktop/node_modules/grpc/src/client.js:554:15
code: 7,
metadata:
Metadata {
_internal_repr:
{ 'google.rpc.help-bin': [Array],
'grpc-status-details-bin': [Array],
'grpc-server-stats-bin': [Array] } } }
Here is my script.
// Imports the Dialogflow library
const dialogflow = require('dialogflow');
// Instantiates clients
const contextsClient = new dialogflow.ContextsClient();
const intentsClient = new dialogflow.IntentsClient();
projectId="1000-1505-ecom-conx-dev"
projectId="conrad-test"
// The path to identify the agent that owns the created intent.
const agentPath = intentsClient.projectAgentPath(projectId);
// Setup intents for ordering a pizza.
// First of all, let's create an intent that triggers pizza order flow.
// Output contexts for ordering pizza. They are used for matching follow-up
// intents. For pizza ordering intents, a "pizza" output context is used for
// hinting the conversation is about pizza ordering, not beer or something
// else. For the first intent, it returns responses asking users to provide
// size information, with a "size" output context for matching the intent
// asking for the size of the pizza.
// Note that session ID is unknown here, using asterisk.
const accountOutputContexts = [
{
name: contextsClient.contextPath(
projectId,
'*' /* sessionId */,
'EComerceAgent'
),
lifespanCount: 5,
},
];
// The result of the matched intent.
const accountResult = {
action: '',
parameters: [
{
displayName: 'Account for',
value: '$application',
entityTypeDisplayName: '#application',
mandatory: true,
prompts: [
'You need appliation access, please describe for which and which permissions do you need?',
'Would you like access to jirra?',
'Would you like access to confluence?',
'Would you like access to AEM?',
],
},
{
displayName: 'user',
value: '$user',
entityTypeDisplayName: '#user',
mandatory: true,
prompts: ['For wich user'],
isList: true,
},
{
displayName: 'permission',
value: '$permission',
// The API provides a built-in entity type #sys.address for addresses.
entityTypeDisplayName: 'permission',
mandatory: true,
prompts: ['Which permission do you need?'],
},
],
messages: [
{
text: {
text: [
'No problem. We will create an account on $application for $user with the following permission: $permission'
],
},
},
{
text: {
text: [
'Reply "check" to place your order. Reply "cancel" to cancel ' +
'your order. You can change your delivery address as well.',
],
},
},
{
quickReplies: {
title:
'No problem. We will create an account on $application for $user with the following permissions: $permission',
quickReplies: ['Create account', 'Cancel']
},
platform: 'PLATFORM_UNSPECIFIED',
},
],
outputContexts: accountOutputContexts,
};
// The phrases for training the linguistic model.
const accountPhrases = [
{type: 'TYPE_EXAMPLE', parts: [{text: 'Get account'}]},
{type: 'TYPE_EXAMPLE', parts: [{text: 'acction'}]},
{
type: 'TYPE_EXAMPLE',
parts: [
{text: 'Create an account '},
{text: 'for', entityType: '#application', alias: 'application'},
{text: ' '},
{text: 'for ', entityType: '#user', alias: 'user'},
{text: 'with the followin permissions ', entityType: '#permission', alias: 'permission'},
],
},
{
type: 'TYPE_EXAMPLE',
parts: [
{text: "I'd like to have access "},
{text: 'to', entityType: '#application', alias: 'application'},
],
}
];
// The intent to be created.
const accountIntent = {
displayName: 'Account',
events: ['create_account'],
// Webhook is disabled because we are not ready to call the webhook yet.
webhookState: 'WEBHOOK_STATE_DISABLED',
trainingPhrases: accountPhrases,
mlEnabled: true,
priority: 500000,
result: accountResult,
};
const accountRequest = {
parent: agentPath,
intent: accountIntent,
};
// Create the pizza intent
intentsClient
.createIntent(accountRequest)
.then(responses => {
console.log('Created account intent:');
logIntent(responses[0]);
})
.catch(err => {
console.error('ERROR:', err);
});
The error is not clear at all, it means that your are not authorized to access the remote ressource without credentials. Here is the quick solution that worked for me :
Go to https://console.cloud.google.com/apis/credentials/serviceaccountkey
Download json auth file (eg. foobar-123.json)
Add environement variable :
export GOOGLE_APPLICATION_CREDENTIALS="/home/me/secure/foobar-123.json"
And the full tutorial & documentation here : https://cloud.google.com/docs/authentication/getting-started
I reported this issue : https://github.com/dialogflow/dialogflow-nodejs-client-v2/issues/28