Sending email SMTP via GMAIL (OAUTH2 and JavaMail) - oauth-2.0

I'm using a web application through which I'm sending an email.
The SMTP host is GMAIL.
I'm using Java 1.8 and JavaMail 1.6.2.
Is there any alternative to the code written below? (credits: https://hellokoding.com/sending-email-through-gmail-smtp-server-with-java-mail-api-and-oauth-2-authorization/)
void sendMail(String smtpServerHost, String smtpServerPort, String smtpUserName, String smtpUserAccessToken, String fromUserEmail, String fromUserFullName, String toEmail, String subject, String body) {
try {
Properties props = System.getProperties();
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.port", smtpServerPort);
props.put("mail.smtp.starttls.enable", "true");
Session session = Session.getDefaultInstance(props);
session.setDebug(true);
MimeMessage msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(fromUserEmail, fromUserFullName));
msg.setRecipient(Message.RecipientType.TO, new InternetAddress(toEmail));
msg.setSubject(subject);
msg.setContent(body, "text/html");
SMTPTransport transport = new SMTPTransport(session, null);
transport.connect(smtpServerHost, smtpUserName, null);
transport.issueCommand("AUTH XOAUTH2 " + new String(BASE64EncoderStream.encode(String.format("user=%s\1auth=Bearer %s\1\1", smtpUserName, smtpUserAccessToken).getBytes())), 235);
transport.sendMessage(msg, msg.getAllRecipients());
} catch (Exception ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, ex.getMessage(), ex);
}
}
Specifically I'm very confused about these two issues:
is the following line truly the only way to set the access token in the Transport?
transport.issueCommand("AUTH XOAUTH2 " + new String(BASE64EncoderStream.encode(String.format("user=%s\1auth=Bearer %s\1\1", smtpUserName, smtpUserAccessToken).getBytes())), 235);
I've been searching throughout the web but I don't seem to find an answer, basically because every other way I've attempted has resulted in NO success.
Is it true that Google has not (yet) implemented a CLIENT credentials grant type?
How else could I send emails through my web application without the user interaction (which I don't have)?
Thank you

Try this:
//TLS and OAuth2
String address = "my.smtpserver.com";
Integer port = 587;
String user = "my_username";
String accesstoken = "my_accesstoken";
String sender = "me#mycompany.com";
String recipients = "you#yourcompany.com;someone#theircompany.com";
String subject = "Test";
String body = "This is a test.";
Properties properties = new Properties();
properties.put("mail.smtp.host", address);
properties.put("mail.smtp.port", port.toString());
properties.put("mail.smtp.starttls.enable", "true");
properties.put("mail.smtp.auth.mechanisms", "XOAUTH2");
properties.put("mail.debug.auth", "true");
Session session = Session.getInstance(properties);
session.setDebug(true);
MimeMessage mimeMessage = new MimeMessage(session);
mimeMessage.setFrom(new InternetAddress(sender));
String s = recipients.replace(';', ',');
mimeMessage.addRecipients(MimeMessage.RecipientType.TO,
InternetAddress.parse(s));
mimeMessage.setSubject(subject);
MimeMultipart mimeMultipart = new MimeMultipart();
MimeBodyPart mimeBodyPart = new MimeBodyPart();
mimeBodyPart.setText(body);
mimeMultipart.addBodyPart(mimeBodyPart);
mimeMessage.setContent(mimeMultipart);
Transport transport = session.getTransport();
transport.connect(user, accesstoken);
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
transport.close();
session = null;

Related

EWS OAuth .net core 2.1

We have a solution today where we use EWS's basic authentication (username and password) with .net Core 2.1, and it works. The problem is that basic authentication will expire in 2020. Therefore, we will transition to the OAuth solution that will work after 2020.
We have tried multiple solutions for this problem, including this: https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth, but some of the methods have been updated (AcquireToken -> AcquireTokenAsync).
It's important that the authentication against azure is not client-based, since everything will happen in backend (web api).
Does anyone have a solution to this problem?
This is our current solution:
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
service.Credentials = new WebCredentials(<email>, <password>);
service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;
service.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
This is an example of what we have tried:
public class Program
{
public static void Run()
{
//tried this as well: string authority = "https://login.windows.net/<devAccountName>.onmicrosoft.com";
string authority = "https://login.microsoftonline.com/<tenantId>/OAuth2/Token";
string clientId = "<clientId>"; // Application ID from Azure
Uri clientAppUri = new Uri("http://localhost:55424/");
Uri resourceHostUri = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
AuthenticationResult authenticationResult = null;
AuthenticationContext authenticationContext = new AuthenticationContext(authority, false);
string errorMessage = null;
try
{
Console.WriteLine("Trying to acquire token");
PlatformParameters platformParams = new PlatformParameters(PromptBehavior.Auto);
authenticationResult = authenticationContext.AcquireTokenAsync("https://outlook.office365.com/EWS/Exchange.asmx", clientId, clientAppUri, platformParams).Result;
}
catch (AdalException ex)
{
errorMessage = ex.Message;
if (ex.InnerException != null)
{
errorMessage += "\nInnerException : " + ex.InnerException.Message;
}
}
catch (ArgumentException ex)
{
errorMessage = ex.Message;
}
if (!string.IsNullOrEmpty(errorMessage))
{
Console.WriteLine("Failed: {0}" + errorMessage);
return;
}
Console.WriteLine("\nMaking the protocol call\n");
ExchangeService exchangeService = new ExchangeService(ExchangeVersion.Exchange2013);
exchangeService.Url = resourceHostUri;
exchangeService.TraceEnabled = true;
exchangeService.TraceFlags = TraceFlags.All;
exchangeService.Credentials = new OAuthCredentials(authenticationResult.AccessToken);
exchangeService.FindFolders(WellKnownFolderName.Root, new FolderView(10));
}
}
We receive this error message after we log in:
AADSTS50001: The application named
https://outlook.office365.com/EWS/Exchange.asmx was not found in the tenant named <tenantId>. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant.

Error.String reference not set to an instance of a String. Parameter name: s (While Sending Email For Account Verification in MVC4 C#)

I am doing an MVC application and trying to send an email to registered user for his account activation and email account verification.
Its working Fine on LocalHost but when i Deployed it on live server it gave me this error:
Error.String reference not set to an instance of a String. Parameter name: s
Following is the Code which i have written for sending email:
var verifyUrl = string.Empty;
verifyUrl = Request.Url.GetLeftPart(UriPartial.Authority) + "/Account/AccountVerify?I=" + NewUserID;
string body = "<html><head><meta content=\"text/html; charset=utf-8\" /></head><body><p>Dear " + objuserdet.Email + "" +
", </p><p>To verify your account, please click the following link:</p>"
+ "<p><a href=\"" + verifyUrl + "\" target=\"_blank\">" + verifyUrl + ""
+ "</a></p><div>Best regards,</div><div>" + NewUserID + " Team.</div><p>Note: Do not forward "
+ "this email. The verify link is private.</p></body></html>";
string To = objuserdet.Email;
string Subject = "Account Activation";
SendEmail(To,Subject,body);
and here is the Email Method:
public void SendEmail(string To, string Subject, string Body)
{
try
{
MailMessage mail = new MailMessage();
// mail.From = new MailAddress(System.Configuration.ConfigurationManager.AppSettings["EmailID"].ToString());
mail.From = new MailAddress("blue.naina9#gmail.com");
mail.To.Add(To.Trim());
mail.Subject = Subject.Trim();
mail.Body = Body;
mail.IsBodyHtml = true;
SmtpClient smtp = new SmtpClient("smtp.gmail.com", 587);
System.Net.NetworkCredential BasicAuthenticationInfo = new System.Net.NetworkCredential("blue.naina9#gmail.com","*******");
smtp.Timeout = 600000;
smtp.UseDefaultCredentials = false;
smtp.Credentials = BasicAuthenticationInfo;
smtp.EnableSsl = true;
smtp.Send(mail);
}
catch (Exception ex)
{
throw ex;
}
}
..
Any Help will be appreciated.
Thanks
Posting stack trace would have helped. How ever the only place I think this kind of error will come is
mail.To.Add(To.Trim());
replace string To = objuserdet.Email;
with
if(!string.IsNullOrEmpty(objuserdet.Email)){
string To = objuserdet.Email;
}
else{
throw new Exception("Email is null!");
}
Check if this works!
This Error Occurs because Gmail blocks Sign-in Request of Sender Email Account From my Application due to change in my current location and Deployment server location(that is in US).
So i added a US based Account for Sending Email and it stats working Fine For me..
Hope this Help Others As well..

passing access token to Jira using OAuth Authentication

I am using OAuth authenication in Jira to test some methods in jira using JIRA Rest Java Client. I have got the access token using OAuth authenication that I need to pass on Jira URL. Here is all what I have got to get access token.
Token is 38ESi9IJW5u3vKDslPFtuV1ZtzDpr6zi
Token secret is cnDSL8oJyuoaQdRcFDwgHzLppSshQn9b
Retrieved request token. go to http://bmh1060149:8080/plugins/servlet/oauth/authorize?oauth_token=38ESi9IJW5u3vKDslPFtuV1ZtzDpr6zi
Access token is : 015CeJiH8cpI5R3OKpNco158kApq8YwV
Now I am passing that access token to Jira URL but I am getting an empty array. Please let me know where I am doing wrong or what changes do I need to incorporate into my code to make this thing work. Here is my code.
public void getAllIssueTypesUsingOAuth(JiraCQCredential jcqcred) {
System.out.println("Inside getAllIssuetypeAssociatedToProject for JiraAdapterImpl");
//String username = jcqcred.getUserName();
//String password = jcqcred.getPassword();
String jiraURL = jcqcred.getJiraUrl();
if (!jiraURL.endsWith("/")) {
jiraURL = jiraURL + "/";
}
try {
String accessToken = JiraAdapterImpl.getAccessToken(); // This method is giving me access token
URL url = new URL(jiraURL + "rest/api/2" + "/" + "issuetype?access_token=" + accessToken);
HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
httpConnection.addRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)");
httpConnection.setRequestProperty("Content-Type", "application/json");
httpConnection.setRequestMethod("GET");
BufferedReader reader = new BufferedReader(new InputStreamReader(httpConnection.getInputStream()));
StringBuilder sb = new StringBuilder();
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line);
}
String issueTypes = sb.toString();
System.out.println("Issuetype associated to project are\n" + issueTypes);
JSONArray jsonArray = new JSONArray(issueTypes);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String issueNames = (String) jsonObject.get("name");
System.out.println(issueNames);
}
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
Its giving me an empty array like []
Hi After searching the little bit I finally managed to a find the solution to the above problem. After getting the access token just pass that access token to the makeAuthenticatedRequest(url, accessToken) method that will give you the resultant data which you want to retrive. Here url is the url which you want to hit to get the resultant data.
private AtlassianOAuthClient getJiraOAuthClient() {
final String baseURI = "http://bmh1060149:8080";
final String consumerKey = "hardcoded-consumer";
final String consumerPrivatekey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDFkPMZQaTqsSXI+bSI65rSVaDzic6WFA3WCZMVMi7lYXJAUdkXo4DgdfvEBO21Bno3bXIoxqS411G8S53I39yhSp7z2vcB76uQQifi0LEaklZfbTnFUXcKCyfwgKPp0tQVA+JZei6hnscbSw8qEItdc69ReZ6SK+3LHhvFUUP1nLhJDsgdPHRXSllgZzqvWAXQupGYZVANpBJuK+KAfiaVXCgA71N9xx/5XTSFi5K+e1T4HVnKAzDasAUt7Mmad+1PE+56Gpa73FLk1Ww+xaAEvss6LehjyWHM5iNswoNYzrNS2k6ZYkDnZxUlbrPDELETbz/n3YgBHGUlyrXi2PBjAgMBAAECggEAAtMctqq6meRofuQbEa4Uq5cv0uuQeZLV086VPMNX6k2nXYYODYl36T2mmNndMC5khvBYpn6Ykk/5yjBmlB2nQOMZPLFPwMZVdJ2Nhm+naJLZC0o7fje49PrN2mFsdoZeI+LHVLIrgoILpLdBAz/zTiW+RvLvMnXQU4wdp4eO6i8J/Jwh0AY8rWsAGkk1mdZDwklPZZiwR3z+DDsDwPxFs8z6cE5rWJd2c/fhAQrHwOXyrQPsGyLHTOqS3BkjtEZrKRUlfdgV76VlThwrE5pAWuO0GPyfK/XCklwcNS1a5XxCOq3uUogWRhCsqUX6pYfAVS6xzX56MGDndQVlp7U5uQKBgQDyTDwhsNTWlmr++FyYrc6liSF9NEMBNDubrfLJH1kaOp590bE8fu3BG0UlkVcueUr05e33Kx1DMSFW72lR4dht1jruWsbFp6LlT3SUtyW2kcSet3fC8gySs2r6NncsZ2XFPoxTkalKpQ1atGoBe3XIKeT8RDZtgoLztQy7/7yANQKBgQDQvSHEKS5SttoFFf4YkUh2QmNX5m7XaDlTLB/3xjnlz8NWOweK1aVysb4t2Tct/SR4ZZ/qZDBlaaj4X9h9nlxxIMoXEyX6Ilc4tyCWBXxn6HFMSa/Rrq662Vzz228cPvW2XGOQWdj7IqwKO9cXgJkI5W84YtMtYrTPLDSjhfpxNwKBgGVCoPq/iSOpN0wZhbE1KiCaP8mwlrQhHSxBtS6CkF1a1DPm97g9n6VNfUdnB1Vf0YipsxrSBOe416MaaRyUUzwMBRLqExo1pelJnIIuTG+RWeeu6zkoqUKCAxpQuttu1uRo8IJYZLTSZ9NZhNfbveyKPa2D4G9B1PJ+3rSO+ztlAoGAZNRHQEMILkpHLBfAgsuC7iUJacdUmVauAiAZXQ1yoDDo0Xl4HjcvUSTMkccQIXXbLREh2w4EVqhgR4G8yIk7bCYDmHvWZ2o5KZtD8VO7EVI1kD0z4Zx4qKcggGbp2AINnMYqDetopX7NDbB0KNUklyiEvf72tUCtyDk5QBgSrqcCgYEAnlg3ByRd/qTFz/darZi9ehT68Cq0CS7/B9YvfnF7YKTAv6J2Hd/i9jGKcc27x6IMi0vf7zrqCyTMq56omiLdu941oWfsOnwffWRBInvrUWTj6yGHOYUtg2z4xESUoFYDeWwe/vX6TugL3oXSX3Sy3KWGlJhn/OmsN2fgajHRip0=";
AtlassianOAuthClient jiraoAuthClient = new AtlassianOAuthClient(consumerKey, consumerPrivatekey, baseURI, "");
return jiraoAuthClient;
}
Here is the code to get Access Token
private String getAccessToken() {
AtlassianOAuthClient jiraoAuthClient = getJiraOAuthClient();
TokenSecretVerifierHolder requestToken = jiraoAuthClient.getRequestToken();
String authorizeUrl = jiraoAuthClient.getAuthorizeUrlForToken(requestToken.token);
String token = requestToken.token;
String tokenSecret = requestToken.secret;
System.out.println("Token is " + requestToken.token);
System.out.println("Token secret is " + requestToken.secret);
System.out.println("Retrieved request token. go to " + authorizeUrl);
String accessToken = jiraoAuthClient.swapRequestTokenForAccessToken(token, tokenSecret, "");
System.out.println("Access token is : " + accessToken);
return accessToken;
}
This is the method you call to retrieve the data.
public void getAllCommentOfIssueUsingOAuth() {
logger.info("Inside getAllCommentOfIssue for JiraAdapterImpl");
AtlassianOAuthClient jiraoAuthClient = getJiraOAuthClient();
String accessToken = getAccessToken();
String url = "your Jira URL";
String responseAsString = jiraoAuthClient.makeAuthenticatedRequest(url, accessToken);
System.out.println(responseAsString);
}
This will give you the resultant JSON data or XML data in resultantString.

WSO2 Identity Server - Oauth 2.0 - Sign-off Example for Java

I wrote a Java based sign-off routine (token revocation) for an Oauth2 authentication flow. See below the code implementation following the cURL protocol instructions in the manual described [ here ]. The program code compiles and works without error message, but after the log-off the user accounts still remains in a connected state under the WSO2 dashboard query.
See below the Servlet class that triggers the log-off function:
class SignoffServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {
try{
String accessToken = (String) req.getSession().getAttribute("access_token");
System.out.println("Start Logoff processing for revoke of the token: " + accessToken);
URL url = new URL (Oauth2Server + "/oauth2/revoke?token="+accessToken);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// new encode with Apache codec (for Java8 use native lib)
String userCredentials = clientId + ":" + clientSecret;
String basicAuth = "Basic " + new String(new Base64().encode(userCredentials.getBytes()));
connection.setRequestProperty ("Authorization", basicAuth);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
connection.addRequestProperty("token", accessToken);
connection.addRequestProperty("token_type_hint", "access_token");
//connection.setRequestProperty("token", accessToken);
// connection.setRequestProperty("token_type_hint", "access_token");
connection.setRequestMethod("POST");
connection.setDoOutput(true);
InputStream content = (InputStream)connection.getInputStream();
BufferedReader in =
new BufferedReader (new InputStreamReader (content));
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
System.out.println("Logoff finished sucessfully");
}
} catch(Exception e) {
System.out.println("Logoff failed, error cause: " + e.toString());
e.printStackTrace();
}
System.out.println("Logoff finished sucessfully");
// return the json of the user's basic info
String html_header = "<html><body>";
String myjson = "<br>Logoff completed sucessfully";
myjson += "<br><br><b><a href='./index.html'>Back to login page</a></b><br>";
String html_footer = "</body></html>";
String mypage = html_header + myjson + html_footer;
resp.setContentType("text/html");
resp.getWriter().println(myjson);
}
}
Advice about what to change in the Java code to activate the sign-off function for Oauth 2.0 is welcome.
Thanks for detailed explanations about the difference between authorization and authentication in Oauth2. See below the code that is able to revoke the valid Oauth2 token:
class SignoffServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {
String outputl = "";
try{
String accessToken = (String) req.getSession().getAttribute("access_token");
// testing .. inhibu acivate this line: // revoke accessToken = "abc";
System.out.println("Start Logoff processing for revoke of the token: " + accessToken);
// URL url = new URL (Oauth2Server + "/oauth2/revoke?token="+accessToken);
// URL url = new URL (Oauth2Server + "/oauth2endpoints/revoke");
URL url = new URL (Oauth2Server + "/oauth2/revoke");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
// new encode with Apache codec (for Java8 use native lib)
String userCredentials = clientId + ":" + clientSecret;
String basicAuth = "Basic " + new String(new Base64().encode(userCredentials.getBytes()));
basicAuth = basicAuth.replace("\\r", "");
basicAuth = basicAuth.replace("\\n", "");
connection.setRequestProperty ("Authorization", basicAuth);
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
// send data
// String str = "{\"token\": \"" + accessToken + "\",\"token_type_hint\":\"access_token\"}";
// example of JSON string "{\"x\": \"val1\",\"y\":\"val2\"}";
//byte[] outputInBytes = str.getBytes("UTF-8");
//OutputStream os = connection.getOutputStream();
//os.write( outputInBytes );
// os.close();
//send request
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.writeBytes("token=" + accessToken);
wr.flush();
wr.close();
// end of new method
InputStream content = (InputStream)connection.getInputStream();
BufferedReader in =
new BufferedReader (new InputStreamReader (content));
String line;
while ((line = in.readLine()) != null) {
// System.out.println(line); // for debug only
outputl += line;
}
} catch(Exception e) {
System.out.println("Logoff failed, error cause: " + e.toString());
e.printStackTrace();
}
System.out.println("Logoff finished successfully");
// return the json of the user's basic info
// customized Apache HTTP GET with header - Claude, 27 August 2015 reading user information
// ===============================================================================================
String tokeninfo = "";
String infourl = Oauth2Server + "/oauth2/userinfo?schema=openid";
StringBuilder infobody = new StringBuilder();
DefaultHttpClient infohttpclient = new DefaultHttpClient(); // create new httpClient
HttpGet infohttpGet = new HttpGet(infourl); // create new httpGet object
// get some info about the user with the access token
String currentToken = (String) req.getSession().getAttribute("access_token");
String bearer = "Bearer " + currentToken.toString();
infohttpGet.setHeader("Authorization", bearer);
try {
HttpResponse response = infohttpclient.execute(infohttpGet); // execute httpGet
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
System.out.println(statusLine);
infobody.append(statusLine + "\n");
HttpEntity e = response.getEntity();
String entity = EntityUtils.toString(e);
infobody.append(entity);
} else {
infobody.append(statusLine + "\n");
// System.out.println(statusLine);
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
tokeninfo = infobody.toString();
infohttpGet.releaseConnection(); // stop connection
}
// User info lookup is done fetching current log status of the token
if (tokeninfo.startsWith("HTTP/1.1 400 Bad Request")) {
tokeninfo = "Token " + currentToken + " was revoked";
};
String html_header = "<html><body>";
String myjson = "<br>Logoff completed successfully";
myjson += "<br>Current Userinfo and Token Status";
myjson += "<br>" + tokeninfo + "<br>";
myjson += "<br><br><b><a href='./index.html'>Back to login page</a></b><br>";
String html_footer = "</body></html>";
String mypage = html_header + myjson + html_footer;
resp.setContentType("text/html");
resp.getWriter().println(myjson);
// to print signoff screen for debug purpose
// resp.getWriter().println(outputl);
}
}
Above doc has been mentioned the way to revoke the access token.Access token revoking and sign-off from OAuth2 authorization server are two different process. As an example; in Facebook, you can revoke the access token which are given for different applications. But it does not mean that you are sign-off from FB or any other application which you already login.
OAuth2 is not an authentication mechanism. It is authorization framework. It does not contain standard way to sign-off from authorization sever. However, there is some custom way which you can use to sign-off (terminate the SSO session in WSO2IS) from WSO2IS which can be used. But, it must be done using the end user's browser (not using the back channel) by calling following url. Please check last part of this for more details
https://localhost:9443/commonauth?commonAuthLogout=true&type=oidc2&sessionDataKey=7fa50562-2d0f-4234-8e39-8a7271b9b273&commonAuthCallerPath=http://localhost:8080/openidconnect/oauth2client&relyingParty=OpenidConnectWebapp

Oauth2 Yahoo Gemini API

I am having trouble calling Yahoo Gemini API to access Yahoo Gemini Advertising from my C# console (desktop) application.
Here are steps I used:
Create an installed application on https://developer.yahoo.com/apps/create/. This gave me both {Client ID} and {Client Secret}.
https://api.login.yahoo.com/oauth2/request_auth?client_id={Client ID} &redirect_uri=oob&response_type=code&language=en-us. This will take me to the yahoo login screen where I sign in. Press the Agree button and the next screen shows the seven-letter authorization code (say nzbcns9). I write down this authorization code.
Then I use the following code to try to get the access token:
class Program
{
static void Main(string[] args)
{
string clientId = {Client ID};
string secret = {Client Secret};
var request = WebRequest.Create(#"https://api.login.yahoo.com/oauth2/get_token");
request.Method = "POST";
SetBasicAuthHeader(request, clientId, secret);
string postData = "grant_type=authorization_code&redirect_uri=oob&code=nzbcns9";
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] byte1 = encoding.GetBytes(postData);
request.ContentLength = byte1.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(byte1, 0, byte1.Length);
dataStream.Close();
request.ContentType = "application/x-www-form-urlencoded";
var response = request.GetResponse();
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
}
static void SetBasicAuthHeader(WebRequest request, String userName, String userPassword)
{
string authInfo = userName + ":" + userPassword;
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
request.Headers["Authorization"] = "Basic " + authInfo;
}
}
Then I get
Unhandled Exception: System.Net.WebException: The remote server returned an error: (401) Unauthorized. at System.Net.HttpWebRequest.GetResponse().
What did I do wrong?
I also try to post the same message using Fiddler, I get
{"error":"invalid_request"}
I tried your code and what worked for me was to put the line request.ContentType = "application/x-www-form-urlencoded"; BEFORE Stream dataStream = request.GetRequestStream();
So this worked:
string postData = "grant_type=authorization_code&redirect_uri=oob&code=nzbcns9";
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] byte1 = encoding.GetBytes(postData);
request.ContentLength = byte1.Length;
request.ContentType = "application/x-www-form-urlencoded";
Stream dataStream = request.GetRequestStream();
dataStream.Write(byte1, 0, byte1.Length);
dataStream.Close();
Neither of these worked for me, but it did work once I changed the SetBasicAuthHeader to use ISO-8859-1 encoding:
static void SetBasicAuthHeader( WebRequest request, String userName, String userPassword )
{
string authInfo = userName + ":" + userPassword;
authInfo = Convert.ToBase64String( Encoding.GetEncoding( "ISO-8859-1" ).GetBytes( authInfo ) );
request.Headers[ "Authorization" ] = "Basic " + authInfo;
}

Resources