Google People API - Not returning email addresses - google-api

I have working the auth flow to authenticate users using google oauth2. Including the default permissions I added the contacts to get access to the users contact.
Once the user accept the authentication then I can get the contacts using this endpoint:
/v1/people/me/connections?personFields=emailAddresses&access_token=****
As you can see I added the emailAddresses but the response for this api call only return the email address for 1 contact of 149
response example:
{"connections"=>
[
{"resourceName"=>"people/c471****", "etag"=>"%EgIBC..."},
{"resourceName"=>"people/c471****", "etag"=>"%EgIBC..."},
........
{
"resourceName"=>"people/c471****", "etag"=>"%EgIBC...",
"emailAddresses"=>[
{"metadata"=>{"primary"=>true, "source"=>{"type"=>"CONTACT", "id"=>"5123*******"}},
"value"=>"*****#gmail.com", "type"=>"home", "formattedType"=>"Home"}
]
}
.........
{"resourceName"=>"people/c471****", "etag"=>"%EgIBC..."},
{"resourceName"=>"people/c471****", "etag"=>"%EgIBC..."},
],
"totalPeople"=> 149,
"totalItems"=>149
}
Why if the response return 149 contact only one of them contains the email address? I could access to the email for all the contacts?

Related

Laravel 8 Socialite check login

is there a way to check if the user has logged in with a Socialite?
because i want to create a post based on this authentication.
what i have done
if (!empty(Socialite::driver('linkedin')->stateless()->user()))
{
$linkedinuser = Socialite::driver('linkedin')->stateless()->user();
dd($linkedinuser);
}
return redirect('/profile/');
i expect to get the dump if user has authenticated with linkedin, or else return profile. Instead, i get an error
GuzzleHttp\Exception\ClientException
Client error: `POST https://www.linkedin.com/oauth/v2/accessToken` resulted in a `400 Bad Request` response: {"error":"invalid_request","error_description":"A required parameter \"code\" is missing"}
how can this be checked ? thanks.

How to exchange JWT token for Credentials in Cognito Identity Pool in .NET Core 3.1 WebApi

Broad Overview: I am trying to create a .Net Core 3.1 WebApi backend that is authenticated against Amazon Cognito. I want to use the Amazon-hosted sign-in page(s) provided by Cognito. I want to leverage Cognito Identity Pool to provide temporary scoped credentials for users after they have logged in. I cannot figure out how to exchange the Cognito token to create the Credentials to call AWS services.
Technology Overview
.NET Core 3.1 WebApi
Amazon Cognito User Pool for initial authentication
Amazon Identity Pool for defining permissions (Roles) for logged in users
Deployed on AWS via API Gateway + Lambda using the AWS Serverless framework (basically CloudFormation)
Currently both of the following work:
Add [Authorize] attribute to a controller endpoint and access the URL in a browser. This re-directs me to the Cognito-hosted login page and, upon successful login, returns me back to the controller/endpoint and I am authorized.
Create a separate Client application and login to AWS Cognito. Pass the JWT token in the Authorization HTTP header when calling APIs from the client and the Authorization succeeds and API access is granted.
In both cases, the access to the API is permitted however the AmazonServiceClient instances that are created in the WebApi are granted the permissions associated with the Lambda function (which is the proper behavior).
Problem
I need to create AmazonServiceClients whose credentials match the Role defined by the Cognito Identity Pool.
To do this, I need to exchange token provided by logging into Cognito User Pool for temporary credentials in the Identity Pool.
Virtually ALL examples and documentation I can find on this process define how to manually login to Cognito using the API (not the hosted web UI), and then using the API response to create a CognitoUser and then get credentials from the Identity Pool using that user.
The closest (though super brief) documentation I can find to do what I need is from AWS here: https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/cognito-creds-provider.html
// Authenticate user through Facebook
string facebookToken = GetFacebookAuthToken();
// Add Facebook login to credentials. This clears the current AWS credentials
// and retrieves new AWS credentials using the authenticated role.
credentials.AddLogin("graph.facebook.com", facebookAccessToken);
While that example uses Facebook, conceptually it should be the same for any provider (Facebook, Google, Twitter, OpenId, etc.).
My Current Attempt
I have registered CognitoAWSCredentials as a Scoped service as it is user-specific and therefore should only exist as long as the API request session exists.
RegionEndpoint region = Configuration.GetAWSOptions().Region;
services.AddScoped(_ => new CognitoAWSCredentials(Settings.CognitoIdentityPoolId, region));
I have created an event handler that gets triggered when the OpenIdConnect event 'OnTokenValidated' is fired. This happens after I login to the Cognito hosted web UI and am redirected back to my API.
In this handler I can call:
CognitoAWSCredentials creds = services.BuildServiceProvider().GetRequiredService<CognitoAWSCredentials>();
creds.AddLogin( ... ??? ...);
(note: since I'm setting all this up in the Startup.ConfigureServices(IServiceCollection services) method, I am building an IServiceProvider instance each time authentication succeeds... which may be inefficient but I haven't figured out another way to access a scoped service inside the ConfigureServices method)
All this preamble to say that I cannot find a set of values for the AddLogin call which allow this test call to succeed:
ImmutableCredentials immCreds = creds.GetCredentials();
Relevant Data Structures
In the event handler where I can call AddLogin, I have access to: Microsoft.AspNetCore.Authentication.OpenIdConnect.TokenValidatedContext which in particular contains:
Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage with:
access_token
id_token
refresh_token
System.IdentityModel.Tokens.Jwt.JwtSecurityToken with:
{
{
"alg": "RS256",
"kid": "**************************"
}. {
"at_hash": "**************************",
"sub": "**************************",
"email_verified": true,
"iss": "https://cognito-idp.ca-central-1.amazonaws.com/**************************",
"cognito:username": "**************************",
"nonce": "**************************",
"aud": "**************************",
"event_id": "**************************",
"token_use": "id",
"auth_time": 1595260191,
"exp": 1595263791,
"iat": 1595260191,
"email": "**************************"
}
}
I have tried using the iss value as the providerName in AddLogin, and either the access_token or id_token but neither work.
Does anyone know what I need to use for AddLogin in order for Cognito to create Identity Pool credentials for me based upon a JWT token from a Cognito User Pool login?
unless I missed it, I haven't seen documentation that states this, but even though all the Issuer fields on the various data structures include the 'https://', you need to strip it before using the Issuer as the providerName on the AddLogin call. ugh.
CognitoAWSCredentials creds = services.BuildServiceProvider().GetRequiredService<CognitoAWSCredentials>();
string shortIssuer = tokenValidatedContext.SecurityToken.Issuer;
if (shortIssuer.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase)) shortIssuer = shortIssuer.Substring("https://".Length);
if (shortIssuer.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase)) shortIssuer = shortIssuer.Substring("http://".Length);
creds.AddLogin(shortIssuer, tokenValidatedContext.TokenEndpointResponse.IdToken);
now, the above code has a problem as the services.BuildServiceProvider(). part means the credentials object I modify isn't global (only local to the service provider I built here I think), but that's a different issue - just noting that in case anyone is copying this code.
services...<other authentication setup>...
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.ClientId = Settings.CognitoClientId;
options.MetadataAddress = CognitoMetadataAddress;
options.ResponseType = OpenIdConnectResponseType.Code;
options.SaveTokens = true;
options.UsePkce = true;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidIssuers = new string[] { Settings.CognitoAuthority },
ValidateAudience = true,
ValidAudiences = new string[] { Settings.CognitoClientId }
};
options.Events = new OpenIdConnectEvents() {
OnTokenValidated = tokenValidatedContext => {
CognitoAWSCredentials creds = services.BuildServiceProvider().GetRequiredService<CognitoAWSCredentials>();
string shortIssuer = tokenValidatedContext.SecurityToken.Issuer;
if (shortIssuer.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase)) shortIssuer = shortIssuer.Substring("https://".Length);
if (shortIssuer.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase)) shortIssuer = shortIssuer.Substring("http://".Length);
creds.AddLogin(shortIssuer, tokenValidatedContext.TokenEndpointResponse.IdToken);
return Task.CompletedTask;
}
};
})
(some code removed to focus on specifically the OpenId Connect event and the CognitoAWSCredentials init)

YouTube Data API credential isn't working when using YouTube Data API

I used YouTube Data API to enable a web-based client I produced for a customer to connect to youtube and list out the videos on her account. This was working fine until the customer left those services unused for 90 days after which the credential was canceled.
I created a new credential but now it doesn't work and I can't figure out the solution. The client authorizes using OAuth then does a YouTube Youtube.Search.list
try{
youtube = getYouTubeService(XXXXXX);
}catch(NullPointerException e){
throw new BasicException("You must connect this system to YouTube before you can load videos. You may do this in Settings.");
}
HashMap<String, String> parameters = new HashMap<String,String>();
parameters.clear();
parameters.put("part", "id,snippet");
parameters.put("forMine", "true");
parameters.put("type", "video");
parameters.put("maxResults", "50");
YouTube.Search.List searchListMineRequest = youtube.search().list(parameters.get("part").toString());
if (parameters.containsKey("maxResults")) {
searchListMineRequest.setMaxResults(Long.parseLong(parameters.get("maxResults").toString()));
}
if (parameters.containsKey("forMine") && parameters.get("forMine") != "") {
boolean forMine = (parameters.get("forMine") == "true") ? true : false;
searchListMineRequest.setForMine(forMine);
}
if (parameters.containsKey("type") && parameters.get("type") != "") {
searchListMineRequest.setType(parameters.get("type").toString());
}
SearchListResponse response = searchListMineRequest.execute();
It is the execute command that produces the problem. The user connects using OAuth in another part of the program and the refresh token is stored for use with the above code. I am new to the google api so excuse if I'm getting some code wrong. I am getting a 403 error. However since the code worked before the credential was cancelled, then I conclude that the problem is with the new credential.
I get the following error message:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "usageLimits",
"message" : "Access Not Configured. YouTube Data API has not been used in project XXXXXXXXXX before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/youtube.googleapis.com/overview?project=XXXXXXXXXX then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.",
"reason" : "accessNotConfigured",
"extendedHelp" : "https://console.developers.google.com/apis/api/youtube.googleapis.com/overview?project=XXXXXXXXXXXXX"
} ],
"message" : "Access Not Configured. YouTube Data API has not been used in project X before or it is disabled. Enable it by visiting.......
}
I found the solution. Once the project credential reached 90 days, my google console project was no longer a functioning project. Some things would work, others not. I had to completely delete the project, connect the youtube data API again and issue a new credential. This resolved the problem.

Unable to send SMTP mails using office365 settings

I am using SMTP mail for sending mail using Laravel. Everything working perfect other than office365 mail settings.
Settings I have used is as below:
SMTP HOST = smtp.office365.com
SMTP PORT = 587
SMTP ENCRYPTION = tls
SMTP USER = username(email)
SMTP PASS = password
Error i am getting is:
554 5.2.0
STOREDRV.Submission.Exception:SendAsDeniedException.MapiExceptionSendAsDenied;
Failed to process message due to a permanent exception with message
Cannot submit message
I have already searched google a lot for this error everybody says about clutter like this link
Solution to this error
But I personally don't find any clutter after followed all the steps mentioned.
I cannot log in this email as it's our client email id and I don't have permission to log in.
I also created one outlook email id and test this email setting.
It worked like charm.
I don't know what is wrong with Client email id.
Any suggestions would be great.
Outlook doesn't provide to send using different from address other than your username to log in.
You need both email address same.
You can add one or more sender in your admin panel after that you can send easily from different addresses.
This error means the user whose credentials you specified in the SMTP connection cannot submit messages on behalf of the user specified in the From and/or Sender MIME headers or the FROM SMTP command.
I face the similar issue and i resolved it right now,
you are most likely facing this issue because your "user" email in the auth option and the "from" email at the mail option are different
make the user and from email same and it will work for you
const transporter = nodemailer.createTransport({
service: 'outlook',
port: 587,
auth: {
user: 'abcde#outlook.com',
pass: '******'
},
tls: {
rejectUnauthorized: false
}
});
// setup email data with unicode symbols
let mailOptions = {
from: "abcde#outlook.com", // sender address
to: 'xyz#gmail.com', // list of receivers
subject: 'Node Contact Request', // Subject line
text: 'Hello world?', // plain text body
html: output // html body
};
// send mail with defined transport object
transporter.sendMail(mailOptions, (error, info) => {
console.log(info);
if (error) {
return console.log(error);
}
console.log('Message sent: %s', info.messageId);
console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info));
});
If your email is not verified you will likely to get more errors
After trying for 4 days, mails started to triggered with port:25, so instead of trying with 587 or 465. Try with other port numbers.
host: "smtp.office***.*",
port:25,
secureConnection: false,
requireTLS: true,
tls: {
ciphers: 'SSLv3'
},
auth: {
user: *,
pass: ***
}
I used Hotmail and had this problem but solved it by editing MAIL_FROM_ADDRESS to be the same as MAIL_USERNAME
Below is my env file set up.
MAIL_MAILER=smtp
MAIL_HOST=smtp-mail.outlook.com
MAIL_PORT=587
MAIL_USERNAME=myemail#hotmail.com (this must be the same as MAIL_FROM_ADDRESS!)
MAIL_PASSWORD=mypassword
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=myemail#hotmail.com (this must be the same as MAIL_USERNAME!)
Everything worked after doing the above.
What works for me is to set DEFAULT_FROM_EMAIL as the EMAIL_HOST_USER.
Working with Office 365 SMTP and Django 3.0.10.
you can also use this Mail-Driver:
https://github.com/motze92/office365-mail
Here you can specify any From-Email Address where your tenant has the permission for. Sent E-Mails will also go into the recipients sent items folder.
for this issue check the jenkins system admin email it is be same as smtp user email
In Spring boot Java you can fix this issue by following code.
application.properties file
spring.mail.properties.mail.smtp.connecttimeout=5000
spring.mail.properties.mail.smtp.timeout=3000
spring.mail.properties.mail.smtp.writetimeout=5000
spring.mail.host=smtp.office365.com
spring.mail.password=password
spring.mail.port=587
spring.mail.username=abc#outlook.com
spring.mail.properties.mail.smtp.starttls.enable=true
security.require-ssl=true
spring.mail.properties.mail.smpt.auth=true
Java class which impliments the mail functionality
#Component
public class MailSenderClass {
#Value("${spring.mail.username}")
private String from;
#Autowired
private JavaMailSender javaMailSender;
public void sendMail(String to, String subject, String body) throws MessagingException {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper;
helper = new MimeMessageHelper(message, true);//true indicates multipart message
helper.setFrom(from) // <--- THIS IS IMPORTANT
helper.setSubject(subject);
helper.setTo(to);
helper.setText(body, true);//true indicates body is html
javaMailSender.send(message);
}
}
Note: you have to helper.setFrom(from) is important , your issue will be resolved by adding that piece of code.

Parse Server Mail gun adapter installation

First off, I am running Parse Server on AWS Elastic Beanstalk.
I see this documentation in the readme file
##### Email verification and password reset
Verifying user email addresses and enabling password reset via email requries an email adapter. As part of the `parse-server` package we provide an adapter for sending email through Mailgun. To use it, sign up for Mailgun, and add this to your initialization code:
```js
var server = ParseServer({
...otherOptions,
// Enable email verification
verifyUserEmails: true,
// set preventLoginWithUnverifiedEmail to false to allow user to login without verifying their email
// set preventLoginWithUnverifiedEmail to true to prevent user from login if their email is not verified
preventLoginWithUnverifiedEmail: false, // defaults to false
// The public URL of your app.
// This will appear in the link that is used to verify email addresses and reset passwords.
// Set the mount path as it is in serverURL
publicServerURL: 'https://example.com/parse',
// Your apps name. This will appear in the subject and body of the emails that are sent.
appName: 'Parse App',
// The email adapter
emailAdapter: {
module: 'parse-server-simple-mailgun-adapter',
options: {
// The address that your emails come from
fromAddress: 'parse#example.com',
// Your domain from mailgun.com
domain: 'example.com',
// Your API key from mailgun.com
apiKey: 'key-mykey',
}
}
});
This doesn't say enough for me though. I am not using an existing express website and I need to know where in the repository to add the mailgun code.
I already have mailgun and have used it in php and I am using this explicitly to reset user passwords.
so again, What file in my parse server folder do I need to add the mailgun adapter?
This is my file structure. If I am being unclear, let me know...
This is where I am at now as far as adding it in. Is this right? My mailgun creds are not in there yet, but I know to do that.
class ParseServer {
constructor({
appId = requiredParameter('You must provide an appId!'),
masterKey = requiredParameter('You must provide a masterKey!'),
appName,
filesAdapter,
push,
loggerAdapter,
logsFolder,
databaseURI,
databaseOptions,
databaseAdapter,
cloud,
collectionPrefix = '',
clientKey,
javascriptKey,
dotNetKey,
restAPIKey,
webhookKey,
fileKey = undefined,
facebookAppIds = [],
enableAnonymousUsers = true,
allowClientClassCreation = true,
oauth = {},
serverURL = requiredParameter('You must provide a serverURL!'),
maxUploadSize = '20mb',
verifyUserEmails = true,
preventLoginWithUnverifiedEmail = false,
cacheAdapter,
emailAdapter: {
module: 'parse-server-simple-mailgun-adapter',
options: {
// The address that your emails come from
fromAddress: 'parse#example.com',
// Your domain from mailgun.com
domain: 'example.com',
// Your API key from mailgun.com
apiKey: 'key-mykey',
}
},
publicServerURL,
customPages = {
invalidLink: undefined,
verifyEmailSuccess: undefined,
choosePassword: undefined,
passwordResetSuccess: undefined
},
parse-server include the mailgun-js module by default so you can use it without any dependency. What you need to do in order to use it is the following:
Create mailgun account and get an ApiKey from there
Include the mail gun simple adapter exactly like how it is included in the code that you provided and just change the values to the relevant values
please notice that the adapter that you add above is only for email verification and password reset. If you want the ability to send an email (e.g. marketing emails, engagement etc.) you can create a cloud code function there you will need to require the mailgun-js module and use the mailgun-js module to send the email exactly like how it is described in here
Then from your client code you will need to trigger this cloud code function and the email will be sent.

Resources