Adding Google Calendar entry without using setUserCredentials - asp.net

I am following the example provided by Google for Market place app at
http://code.google.com/googleapps/marketplace/tutorial_dotnet.html
I got the google authentication working as in the example ,
My next task is to add a entry to Google calendar. I found following code for that, and it is also working fine
CalendarService service = new CalendarService(APPLICATION_NAME);
service.setUserCredentials(vUserName, vPassword);
Google.GData.Calendar.EventEntry entry = new Google.GData.Calendar.EventEntry();
// Set the title and content of the entry.
entry.Title.Text = title;
entry.Content.Content = contents;
// Set a location for the event.
Where eventLocation = new Where();
eventLocation.ValueString = location;
entry.Locations.Add(eventLocation);
When eventTime = new When(startTime, endTime);
entry.Times.Add(eventTime);
Uri postUri = new Uri("http://www.google.com/calendar/feeds/default/private/full");
// Send the request and receive the response:
AtomEntry insertedEntry = service.Insert(postUri, entry);
The problem i have is the following line, If i give my username and password it will work
service.setUserCredentials(vUserName, vPassword);
i have authenticated the user as in google example. So I don’t know the username and password of other users login to my site using their gmail.
How do i add a calender entry with the information i have?
I have seen several examples with RequestFactory authenticating the user. but couldn't find complete example that I can use

you will need to create a .pfx cert file and upload it to google and place it on your server.
create your AuthSubRequest URL
<asp:HyperLink ID="GotoAuthSubLink" runat="server"/>
GotoAuthSubLink.Text = "Login to your Google Account";
GotoAuthSubLink.NavigateUrl = AuthSubUtil.getRequestUrl("(return url)http://www.example.com/RetrieveToken", "https://www.google.com/calendar/feeds/", false, true);
after the person clicks on your auth link they are returned to your return url. get your session token as follows
String sessionToken = ""; //Save this for making your calls.
String certFile = "D:\\websites\\yourwebsite.com\\google.pfx";
String result = GetAuthSubSessionToken(Request["token"]);
protected AsymmetricAlgorithm GetRsaKey()
{
X509Certificate2 cert = new X509Certificate2(certFile, "");
RSACryptoServiceProvider privateKey = cert.PrivateKey as RSACryptoServiceProvider;
return privateKey;
}
public string GetAuthSubSessionToken(string singleUseToken)
{
string gatStr = "";
try
{
AsymmetricAlgorithm rsaKey = GetRsaKey();
try
{
sessionToken = AuthSubUtil.exchangeForSessionToken(singleUseToken, rsaKey).ToString();
gatStr = "Session Token = " + SessionToken;
}
catch (Exception e)
{
gatStr = "Error: I appears that the Google authentication server is experiencing an error. Try the authorizaton link again in a few minutes. <a href=\""
+ rtnUrl + "\" title=\"" + e.Message + "\">continue</a>";
}
}
catch (Exception E)
{
gatStr = "Error: rsa " + E.Message + E.StackTrace;
}
return gatStr;
}
save the session token and use CreateCalendarService in subsequent calls to create your calendar service.
public CalendarService CreateCalendarService()
{
GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("cl", "YourName-calendarApp-1");
authFactory.Token = sessionToken;
authFactory.PrivateKey = GetRsaKey();
CalendarService cs = new CalendarService(authFactory.ApplicationName);
cs.RequestFactory = authFactory;
return cs;
}

Related

redirect_uri_mismatch in Google APIs in ASP.NET

I am trying to upload video on my YouTube channel using ASP.NET Web Form. I created developer account and tested it working using JavaScript based solution which requires login every-time to upload a video.
I want users of my website to upload video directly on my channel and every auth should be in code behind, user should not be prompted to login. For this I wrote following class:
public class UploadVideo
{
public async Task Run(string filePath)
{
string CLIENT_ID = "1111111111111111111111.apps.googleusercontent.com";
string CLIENT_SECRET = "234JEjkwkdfh1111";
var youtubeService = AuthenticateOauth(CLIENT_ID, CLIENT_SECRET, "SingleUser");
var video = new Video();
video.Snippet = new VideoSnippet();
video.Snippet.Title = "Default Video Title";
video.Snippet.Description = "Default Video Description";
video.Snippet.Tags = new string[] { "tag1", "tag2" };
video.Snippet.CategoryId = "22"; // See https://developers.google.com/youtube/v3/docs/videoCategories/list
video.Status = new VideoStatus();
video.Status.PrivacyStatus = "unlisted"; // or "private" or "public"
using (var fileStream = new FileStream(filePath, FileMode.Open))
{
var videosInsertRequest = youtubeService.Videos.Insert(video, "snippet,status", fileStream, "video/*");
videosInsertRequest.ProgressChanged += videosInsertRequest_ProgressChanged;
videosInsertRequest.ResponseReceived += videosInsertRequest_ResponseReceived;
await videosInsertRequest.UploadAsync();
}
}
void videosInsertRequest_ProgressChanged(Google.Apis.Upload.IUploadProgress progress)
{
switch (progress.Status)
{
case UploadStatus.Uploading:
//Console.WriteLine("{0} bytes sent.", progress.BytesSent);
break;
case UploadStatus.Failed:
//Console.WriteLine("An error prevented the upload from completing.\n{0}", progress.Exception);
break;
}
}
void videosInsertRequest_ResponseReceived(Video video)
{
Console.WriteLine("Video id '{0}' was successfully uploaded.", video.Id);
}
public static YouTubeService AuthenticateOauth(string clientId, string clientSecret, string userName)
{
string[] scopes = new string[] { YouTubeService.Scope.Youtube, // view and manage your YouTube account
YouTubeService.Scope.YoutubeForceSsl,
YouTubeService.Scope.Youtubepartner,
YouTubeService.Scope.YoutubepartnerChannelAudit,
YouTubeService.Scope.YoutubeReadonly,
YouTubeService.Scope.YoutubeUpload};
try
{
// here is where we Request the user to give us access, or use the Refresh Token that was previously stored in %AppData%
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets { ClientId = clientId, ClientSecret = clientSecret }
, scopes
, userName
, CancellationToken.None
, new FileDataStore("Daimto.YouTube.Auth.Store")).Result;
YouTubeService service = new YouTubeService(new YouTubeService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "YouTube Data API Sample",
});
return service;
}
catch (Exception ex)
{
//Console.WriteLine(ex.InnerException);
return null;
}
}
}
Now using this class into Page_Load() of default.aspx, as given below:
protected void Page_Load(object sender, EventArgs e)
{
try
{
string path = "C:/Users/abhi/Desktop/TestClip.mp4";
new UploadVideo().Run(path).Wait();
}
catch (AggregateException ex)
{
//catch exceptions
}
}
When I run this (default.aspx) page, i see http://localhost:29540/default.aspx spins, so I used them on Google Developer Console as given below:
Upon running http://localhost:29540/default.aspx opens a new tab which displays "redirect_uri_mismatch" error as given below:
At this point if I look in browser address, I see redirect_uri is set to http://localhost:37294/authorize and I just manually change this to http://localhost:29540/default.aspx which generates a token.
So, can you suggest where to make changes in above code so that request uri fills up correctly from my app side.
A day waste then I came to know below redirect URL is working for all localhost web applications. So you need to use below URL on google developer console web application's "Authorized redirect URIs".
http://localhost/authorize/
For anybody still having this issue in 2022, I figured out a solution. If you are using https://localhost:portnumb as your redirect uri, just use https://127.0.0.1:sameportnumb as your redirect uri. It ended up working for me

OneDrive for Business :"invalid_request","error_description":"AADSTS90014: The request body must contain the following parameter: 'grant_type

I'm trying to integrate the OneDrive for Busines to a Web Form App.
For this I use the documentation given at this url
In web Form App I have two Pages:
First one is Login page which have a button for login
On login button click I create a GET Request to OneDrive for Business API using the following code:
HttpClient client = new HttpClient();
Redirecturi = Uri.EscapeDataString(Redirecturi);
string url = string.Format("https://login.windows.net/common/oauth2/authorize?response_type=code&client_id={0}&redirect_uri={1}", ClienId, Redirecturi);
var response = client.GetAsync(url);
var json = response.Result.Content.ReadAsStringAsync();
Label2.Text = json.Result;
When I click the login button it takes me to micorosoft login service and sends me back to callback.aspx page with access code (Redirect URI configured on azure)
I got the access code.
On the second page I redeem the access code and make a POST request to get the Authentication token.
Here is the code for the second page:
private string BaseUri="https://login.windows.net/common/oauth2/token";
public string Redirecturi = "http://localhost:51642/CallBack.aspx";
public string ResourcesId = "https://api.office.com/discovery/";
private string ClienId = "180c6ac4-5829-468e-.....-822405804862"; ///truncated//azure
private string ClientSecert = "G4TAQzD8d7C4...OE6m366afv8XKbTCcyXr4=";//truncated
protected void Page_Load(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(Request.QueryString[OAuthConstants.AccessToken]))
{
// There is a token available already. It should be the token flow. Ignore it.
return;
}
if (!string.IsNullOrEmpty(Request.QueryString[OAuthConstants.Code]))
{
string _accessCode = Request.QueryString[OAuthConstants.Code];
HttpClient client = new HttpClient();
// BaseUri = Uri.EscapeDataString(BaseUri);
Redirecturi = Uri.EscapeDataString(Redirecturi);
ResourcesId = Uri.EscapeDataString(ResourcesId);
string url = string.Format("{0}?client_id={1}&redirect_uri={2}&grant_type=authorization_code&client_secret={3}&code={4}&grant_type=authorization_code&resource={5}", BaseUri, ClienId, Redirecturi, ClientSecert, _accessCode, ResourcesId);
var response = client.PostAsync(url, null);
var json = response.Result.Content.ReadAsStringAsync();
Response.Write(json);
}
}
But instead of Response I am get the following error. Which say include the grant_type in url. I have already added (you can check in code).
I get same error the same error without including it.
Here is the error
{"error":"invalid_request","error_description":"AADSTS90014: The request body must contain the following parameter: 'grant_type'.\r\nTrace ID: 2adb3a7f-ceb1-4978-97c4-3dc2d3cc3ad4\r\nCorrelation ID: 29fb11a0-c602-4891-9299-b0b538d75b5f\r\nTimestamp: 2015-07-15 09:58:42Z","error_codes":[90014],"timestamp":"2015-07-15 09:58:42Z","trace_id":"2adb3a7f-ceb1-4978-97c4-3dc2d3cc3ad4","correlation_id":"29fb11a0-c602-4891-9299-b0b538d75b5f","submit_url":null,"context":null}
Please help to know where or what is getting wrong.
Any kind of help will be appreciable
You're adding the parameters to the request querystring. You have to post the data in the request body.
var content = new StringContent(
"grant_type=authorization_code" +
"&client_id=" + ClienId +
"&redirect_uri=" + Redirecturi +
"&client_secret=" + ClientSecert +
"&code=" + _accessCode +
"&resource=" + ResourcesId,
Encoding.UTF8,
"application/x-www-form-urlencoded");
var response = httpClient.PostAsync(BaseUri, content);
var result = response.Result.Content.ReadAsStringAsync();
use FormUrlEncodedContent instead of StringContent (form data post)
var formContent = new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "client_id", clientId },
{ "client_secret", clientSecret },
{ "code", authCode },
{ "redirect_uri", redirectUri },
{ "grant_type", "authorization_code" }
});
var response = await httpClient.PostAsync("https://login.microsoftonline.com/common/oauth2/token", formContent);
Sharing for future readers because this error is not specific to OneDrive only but can arise in other Microsoft tools
I was getting this error when working with Microsoft Bot Framework's Skype bot. In my case the bot file the appId and appSecret was wrongly set to clientId and clientSecret
Changing the same to appId and appSecret fixed the issue.

Google Calendar API v3 .NET authentication with Service Account or Web Application ID

I need to connect a Google Calendar on my .NET 4.5 application (VS 2013 project).
I want to get all the information from the Calendar, such as: events, dates, notes, names, guests, etc...
I used the Google Developer Console to create both a Web Application Client ID and a Service Account, but I get different errors and no results.
I've implemented 2 different methods, one to login with Web Application Client ID and one to use Service Account.
This is the common ASPX page
public partial class Calendar : System.Web.UI.Page
{
// client_secrets.json path.
private readonly string GoogleOAuth2JsonPath = ConfigurationManager.AppSettings["GoogleOAuth2JsonPath"];
// p12 certificate path.
private readonly string GoogleOAuth2CertificatePath = ConfigurationManager.AppSettings["GoogleOAuth2CertificatePath"];
// #developer... e-mail address.
private readonly string GoogleOAuth2EmailAddress = ConfigurationManager.AppSettings["GoogleOAuth2EmailAddress"];
// certificate password ("notasecret").
private readonly string GoogleOAuth2PrivateKey = ConfigurationManager.AppSettings["GoogleOAuth2PrivateKey"];
// my Google account e-mail address.
private readonly string GoogleAccount = ConfigurationManager.AppSettings["GoogleAccount"];
protected void Page_Load(object sender, EventArgs e)
{
// Enabled one at a time to test
//GoogleLoginWithServiceAccount();
GoogleLoginWithWebApplicationClientId();
}
}
Using Web Application Client ID
I've tried to configure the redirect URIs parameter for the JSON config file, but no URI seems to work. I'm on development environment so I'm using IIS Express on port 44300 (SSL enabled). The error I'm getting is:
Error: redirect_uri_mismatch
Application: CalendarTest
The redirect URI in the request: http://localhost:56549/authorize/ did not match a registered redirect URI.
Request details
scope=https://www.googleapis.com/auth/calendar
response_type=code
redirect_uri=http://localhost:56549/authorize/
access_type=offline
client_id=....apps.googleusercontent
The code
private void GoogleLoginWithWebApplicationClientId()
{
UserCredential credential;
// This example uses the client_secrets.json file for authorization.
// This file can be downloaded from the Google Developers Console
// project.
using (FileStream json = new FileStream(Server.MapPath(GoogleOAuth2JsonPath), FileMode.Open,
FileAccess.Read))
{
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(json).Secrets,
new[] { CalendarService.Scope.Calendar },
"...#developer.gserviceaccount.com", CancellationToken.None,
new FileDataStore("Calendar.Auth.Store")).Result;
}
// Create the service.
CalendarService service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "CalendarTest"
});
try
{
CalendarListResource.ListRequest listRequest = service.CalendarList.List();
IList<CalendarListEntry> calendarList = listRequest.Execute().Items;
foreach (CalendarListEntry entry in calendarList)
{
txtCalendarList.Text += "[" + entry.Summary + ". Location: " + entry.Location + ", TimeZone: " +
entry.TimeZone + "] ";
}
}
catch (TokenResponseException tre)
{
txtCalendarList.Text = tre.Message;
}
}
Using Service Account (preferred)
I can reach the CalendarListResource.ListRequest listRequest = service.CalendarList.List(); line, so I guess the login works, but then, when I want the list on IList<CalendarListEntry> calendarList = listRequest.Execute().Items; I get the following error:
Error:"unauthorized_client", Description:"Unauthorized client or scope in request.", Uri:""
The code
private void GoogleLoginWithServiceAccount()
{
/*
* From https://developers.google.com/console/help/new/?hl=en_US#generatingoauth2:
* The name of the downloaded private key is the key's thumbprint. When inspecting the key on your computer, or using the key in your application,
* you need to provide the password "notasecret".
* Note that while the password for all Google-issued private keys is the same (notasecret), each key is cryptographically unique.
* GoogleOAuth2PrivateKey = "notasecret".
*/
X509Certificate2 certificate = new X509Certificate2(Server.MapPath(GoogleOAuth2CertificatePath),
GoogleOAuth2PrivateKey, X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(GoogleOAuth2EmailAddress)
{
User = GoogleAccount,
Scopes = new[] { CalendarService.Scope.Calendar }
}.FromCertificate(certificate));
// Create the service.
CalendarService service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "CalendarTest"
});
try
{
CalendarListResource.ListRequest listRequest = service.CalendarList.List();
IList<CalendarListEntry> calendarList = listRequest.Execute().Items;
foreach (CalendarListEntry entry in calendarList)
{
txtCalendarList.Text += "[" + entry.Summary + ". Location: " + entry.Location + ", TimeZone: " +
entry.TimeZone + "] ";
}
}
catch (TokenResponseException tre)
{
txtCalendarList.Text = tre.Message;
}
}
I prefer the Service Account login because there's no need for user to login with consent screen, since the application should do it by itself each time it needs to refresh. Is it possible to use a Service Account with free Google Account or do I need Admin console? I've read many conflicting reports about that...
Anyway, looking around with Google and also in StackOverflow, I didn't find a solution. I've seen and tried many questions and solutions but with no results. Some examples:
Keep getting Error: redirect_uri_mismatch using youtube api v3
Google Calendar redirect_uri_mismatch
Google API Calender v3 Event Insert via Service Account using Asp.Net MVC
https://developers.google.com/google-apps/calendar/instantiate
https://groups.google.com/forum/#!topic/google-calendar-api/MySzyAXq12Q
Please help! :-)
UPDATE 1 - Using Service Account (preferred) - SOLVED!
The only problem in my code was:
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(GoogleOAuth2EmailAddress)
{
//User = GoogleAccount,
Scopes = new[] { CalendarService.Scope.Calendar }
}.FromCertificate(certificate));
There's NO NEED for User = GoogleAccount.
There is definitely something wrong with your authentication. Here is a copy of my Service account authentication method.
/// <summary>
/// Authenticating to Google using a Service account
/// Documentation: https://developers.google.com/accounts/docs/OAuth2#serviceaccount
/// </summary>
/// <param name="serviceAccountEmail">From Google Developer console https://console.developers.google.com</param>
/// <param name="keyFilePath">Location of the Service account key file downloaded from Google Developer console https://console.developers.google.com</param>
/// <returns></returns>
public static CalendarService AuthenticateServiceAccount(string serviceAccountEmail, string keyFilePath)
{
// check the file exists
if (!File.Exists(keyFilePath))
{
Console.WriteLine("An Error occurred - Key file does not exist");
return null;
}
string[] scopes = new string[] {
CalendarService.Scope.Calendar , // Manage your calendars
CalendarService.Scope.CalendarReadonly // View your Calendars
};
var certificate = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
try
{
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = scopes
}.FromCertificate(certificate));
// Create the service.
CalendarService service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Calendar API Sample",
});
return service;
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
return null;
}
}
I have a tutorial on it as well. My tutorial Google Calendar API Authentication with C# The code above was ripped directly from my sample project Google-Dotnet-Samples project on GitHub
Note/headsup: Remember that a service account isn't you. It does now have any calendars when you start you need to create a calendar and insert it into the calendar list before you are going to get any results back. Also you wont be able to see this calendar though the web version of Google Calendar because you cant log in as a service account. Best work around for this is to have the service account grant you permissions to the calendar.

how to skip facebook app permissions dialog

Here, I am trying to authenticate user via login and after that I want to skip permissions dialog. But I am unable to achieve this, as it always asking for permissions for app to the user. My intention is if user is not logged into the facebook he/she should be prompted for facebook login and then I will fetch public information by using method Get("/me"). Let me know what I am doing wrong here.
public string GetFBAccessToken(string strAppID, string strAppSecret, string strUrl)
{
// Declaring facebook client type
var vFB = new FacebookClient();
string strAccessTok = string.Empty;
try
{
if (!string.IsNullOrEmpty(strAppID) && !string.IsNullOrEmpty(strAppSecret) && !string.IsNullOrEmpty(strUrl))
{
// Getting login url for facebook
var loginUrl = vFB.GetLoginUrl(new
{
client_id = strAppID,
client_secret = strAppSecret,
redirect_uri = strUrl,
response_type = "code",
state = "returnUrl",
//scope = "",
display = "popup"
});
// Redirecting the page to login url
if (HttpContext.Current.Request.QueryString["code"] == null)
{
HttpContext.Current.Response.Redirect(loginUrl.AbsoluteUri);
}
// Fetching the access token from query string
if (HttpContext.Current.Request.QueryString["code"] != null)
{
dynamic result = vFB.Post("oauth/access_token", new
{
client_id = strAppID,
client_secret = strAppSecret,
redirect_uri = strUrl,
code = HttpContext.Current.Request.QueryString["code"]
});
// Getting access token and storing in a variable
strAccessTok = result.access_token;
}
}
return strAccessTok;
}
catch (Exception ex)
{
//if (HttpContext.Current.Request.QueryString["response_type"] == "code")
//{
// var fb = new FacebookClient();
// var details = fb.Get("/me");
//}
return strAccessTok;
}
}
Regardless to the platform/ language you are using; solution can be as follows.
check use's logged in status. https://developers.facebook.com/docs/reference/javascript/FB.getLoginStatus/
based on Response status, forcefully call your action (i.e. Log in, Get Permission or any additional action if user is already connected). For Log in check this reference document from FB. https://developers.facebook.com/docs/facebook-login/login-flow-for-web/
No. You cannot skip the Login Dialog.
In fact, it is really important for an APP owner to build a trust relationship with your users. I would recommend you to follow the Login Best Practices while authenticating the users using your APP.

facing problem in facebook connect api using asp.net

I am using Facebook connect API to grab my friendlist. It redirects me to the login page.
but when I provide credentials it throws an error something like this;
API Error Code: 100
API Error Description: Invalid parameter
Error Message: Requires valid next URL.
Here is the code;
//my actual values are mentioned in the key
_fbService.ApplicationKey = "KEY";
_fbService.Secret = "Key";
_fbService.IsDesktopApplication = false;
string sessionKey = Session["Facebook_session_key"] as String;
string userId = Session["Facebook_userId"] as String;
// When the user uses the Facebook login page, the redirect back here will will have the auth_token in the query params
string authToken = Request.QueryString["auth_token"];
if (!String.IsNullOrEmpty(sessionKey))
{
_fbService.SessionKey = sessionKey;
_fbService.UserId = userId;
}
else if (!String.IsNullOrEmpty(authToken))
{
_fbService.CreateSession(authToken);
Session["Facebook_session_key"] = _fbService.SessionKey;
Session["Facebook_userId"] = _fbService.UserId;
Session["Facebook_session_expires"] = _fbService.SessionExpires;
}
else
{
Response.Redirect(#"http://www.Facebook.com/login.php?api_key=" + _fbService.ApplicationKey + #"&v=1.0");
}
if (!IsPostBack)
{
// Use the FacebookService Component to populate Friends
//MyFriendList.Friends = _fbService.GetFriends();
MyFriendlist.Friends = _fbService.GetFriends();
}
Does anyone knows how to get rid of this?
Thanks in advance.
Instead of redirecting to the url, try using
base.login=true;
//Response.Redirect(#"http://www.Facebook.com/login.php?api_key=" + _fbService.ApplicationKey + #"&v=1.0");
or
Response.Redirect(#"http://www.Facebook.com/login.php?api_key=" + _fbService.ApplicationKey + #"&v=1.0&next=http://apps.facebook.com/yourapplication");

Resources