how to get email id using oauth - java

I'm trying to get user profile information by using following code. I'm using scribe to get the information. I'm able to get familyName and givenName etc. but it is not returning me the email id.
I'm using the following code:
OAuthRequest request = new OAuthRequest(
Verb.GET,
"https://social.yahooapis.com/v1/me/guid? format=xml"
);
service.signRequest(accessToken, request);
request.addHeader("realm", "yahooapis.com");
Response response = request.send();
And this is the response I got:
{
"profile": {
"guid":"CGGT5LNT7NXGFK64QW7FQN5UQM",
"ageCategory":"A",
"familyName":"gto",
"givenName":"CTSDemo",
"image": {
"height":192,
"imageUrl":"https://s.yimg.com/dh/ap/social/profile/profile_b192.png",
"size":"192x192",
"width":192
},
"intl":"us",
"jurisdiction":"us",
"lang":"en-US",
"location":"Bangalore",
"memberSince":"2014-08-03T08:23:27Z",
"nickname":"CTSDemo",
"notStored":false,
"nux":"3",
"profileMode":"PUBLIC",
"profileStatus":"ACTIVE",
"profileUrl":"http://profile.yahoo.com/CGGT5LNT7NXGFK64QW7FQN5UQM",
"updated":"2014-08-29T12:00:44Z",
"isConnected":false,
"profileHidden":false,
"bdRestricted":true,
"profilePermission":"PUBLIC",
"uri":"https://social.yahooapis.com/v1/user/CGGT5LNT7NXGFK64QW7FQN5UQM/profile",
"cache":true
}
}

I Found Solution!
You need to change your application's permission in the yahoo.
Url, which provide user info: https://social.yahooapis.com/v1/user/me/profile
And don't forget to add header Authorization: Bearer [your_access_token]

Related

Unable to subscribe web-hook for SharePoint online

We are unable to subscribe web-hook for SharePoint online from our Spring-Boot application.
Providing valid notification URL(https enabled, publicly accessible, valid domain name, Post method) as parameter while consuming rest API in order to subscribe web-hook.
#PostMapping(value = "/spnotification")
#ResponseBody
public ResponseEntity<String> handleSPValidation(#RequestParam final String validationtoken) {
LOG.info("validationToken : " + validationtoken);
return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN)
.body(validationtoken);
}
And on this notification URL end-point, we are able to receive validation string from share-point as parameter and same string we are retiring in less then 5 sec with content-type text/plain and http status code 200 as response.
still getting 400 bad request with below error message.
400 Bad Request: [{"error":{"code":"-1, System.InvalidOperationException","message":{"lang":"en-US","value":"Failed to validate the notification URL 'https://example.com/notification-listener-service/api/webhook/spnotification'."}}}]
Note : We are following this API documentation to subscribe web-hook.
We tried Graph API also for the same purpose but in that case getting below error.
"error": {
"code": "InvalidRequest",
"message": "The server committed a protocol violation. Section=ResponseHeader Detail=CR must be followed by LF"
}
Please find this diagram for more understanding on this issue.
We really appreciate if someone can help us on the same.
Please check the #PostMapping(value = "/notification", headers = { "content-type=text/plain" })
#PostMapping(value = "/notification", headers = { "content-type=text/plain" })
#ResponseBody
public ResponseEntity<String> handleSPValidation(#RequestParam final String validationtoken) {
LOG.info("validationToken : " + validationtoken);
return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN)
.body(validationtoken);
}
GitHub Code

EWS API to access Office365 with oAuth2

We have a Daemon application that uses the EWS API to access office365/Exchange server with basic authentication. I am trying to implement the Oauth2. There are a lot of documents. However, they are often out of date and caused more confusion. I followed this document https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-daemon-overview, which seems up-to-date. I did the following steps:
Register App
Document: https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-daemon-app-registration
- Registered a secret with application password in Azure AD, i.e. certificate is used. The generated secret is recorded.
- selected the “Accounts in this organizational directory only”.
- Requested API Permission for Application permissions for Exchange full_access_as_app and Mail.Read. Admin consent is granted.
Get Token
Document: https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-daemon-acquire-token?tabs=java
I prototyped to use Protocol to get token
POST /{tenant}/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id={myAppClientId}
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&client_secret={myAppSecret}
&grant_type=client_credentials
I got token with
{
"token_type": "Bearer",
"expires_in": 3599,
"ext_expires_in": 3599,
"access_token": "……thetoken…"
}
Call EWS API in my App
My App works with the Basic Authentication. I modified it by adding the Authorization header ("Authorization", "Bearer " + accessToken); Basially the prepareWebRequest() function is overriden by adding the Authorization header. Compared with a Basic Authentication case, the request has the additional Authorization header with the Bearer token.
For the same EWS API call that the Basic Authorization had worked, the response is 401 with
x-ms-diagnostics
2000003;reason="The audience claim value is invalid for current resource. Audience claim is 'https://graph.microsoft.com', request url is 'https://outlook.office365.com/EWS/Exchange.asmx' and resource type is 'Exchange'.";error_category="invalid_resource"
Researched in stackoverflow, people suggested to use the following as scope value to get token in step 2:
https://outlook.office365.com/full_access_as_app
https://outlook.office.com/Mail.Read
I tried and both returned “invalid_scope” error. It seems both worked before but not anymore. Following the working scope value format, I tried to use https://outlook.office.com/.default as scope value. I was able to get a token! However, when I use this token in EWS API to access the mailbox, I got 500 error instead of the 401.
What are the right things to do to make it work? What is the right Scope to access an office365 mail box?
More Code Snippets
This is a new class added for oauth2
package microsoft.exchange.webservices.data;
import java.util.Map;
public final class BearerTokenCredentials extends ExchangeCredentials {
private static final String BEARER_TOKEN_FORMAT_REGEX = "^[-._~+/A-Za-z0-9]+=*$";
private static final String AUTHORIZATION = "Authorization";
private static final String BEARER_AUTH_PREAMBLE = "Bearer ";
private String token;
public String getToken() {
return token;
}
public BearerTokenCredentials(String bearerToken) {
if (bearerToken == null) {
throw new IllegalArgumentException("Bearer token can not be null");
}
this.validateToken(bearerToken);
this.token = bearerToken;
}
protected void validateToken(String bearerToken) throws IllegalArgumentException {
if (!bearerToken.matches(BEARER_TOKEN_FORMAT_REGEX)) {
throw new IllegalArgumentException("Bearer token format is invalid.");
}
}
#Override
public void prepareWebRequest(HttpWebRequest request) {
Map<String, String> headersMap = request.getHeaders();
String bearerValue = BEARER_AUTH_PREAMBLE + token;
headersMap.put(AUTHORIZATION, bearerValue);
//headersMap.put("X-AnchorMailbox","esj_office365_imap#genesyslab.onmicrosoft.com");
request.setHeaders(headersMap);
}
}
Use the token to acceess EWS/Exchange ews-java-api 2.0-patched
ExchangeService service = new
ExchangeService(ExchangeVersion.Exchange2010_SP2); //version is
Exchange2010_SP2
service.setTraceEnabled(true);
BearerTokenCredentials credentials = new BearerTokenCredentials("thetoken");
service.setCredentials(credentials);
service.setUrl(new
URI(host));//https://outloook.office365.com/EWS/Exchange.asmx
try{
Folder.bind(service, WellKnownFolderName.Inbox);
}catch(Exception e)
{
//The remote server returned an error: (500)Internal Server Error
}
The code you use to connect to the Office365 Mailbox still needs to use EWS Impersonation eg
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, mailboxName);
Where MailboxName is the Mailbox you want to connect to.

AppEngine endpoint framework v2 sample authentication with firebase return response 401 Invalid credentials

I'm using the appengine endpoints-framework-v2 java sample. In this sample there is an endpoint called getUserEmailFirebase which should authenticated firebase user but it does not work
#ApiMethod(
path = "firebase_user",
httpMethod = ApiMethod.HttpMethod.GET,
authenticators = {EspAuthenticator.class},
issuerAudiences = {#ApiIssuerAudience(name = "firebase",
audiences = {"my-project-id"})}
)
public Email getUserEmailFirebase(User user) throws UnauthorizedException {
if (user == null) {
throw new UnauthorizedException("Invalid credentials");
}
Email response = new Email();
response.setEmail(user.getEmail());
return response;
}
I tried to send the request with an Authorization header inculding the firebase user id token but I'm getting 401 response, Also tried to add 'Bearer ' at the begining of the token but I get the same result. Even tried to follow this appengine guide Authenticating Users (Frameworks) without success.
The token is retrieved by AngularFire SDK using firebaseUser.getIdToken(), I have used the Firebase server sdk to authenticated users successfuly but it doesn't work using the above method
Can you help?

Issue creating repository github v3 api via Java

I'm trying to send a post request to github to create a repository. I've got oauth 2.0 working and the request is correctly signed but github is just returning "Problems parsing JSON"
I'm using Scribe for the oauth side of things and as far as I can tell I've added JSON to the URL but I'm not 100% certain I'm doing it correctly, or am I just missing headers or something?
#POST
#Path("create_repo/{userid}")
#Produces(MediaType.APPLICATION_JSON)
public Response createRepo(#PathParam("userid") String userid) {
OAuthService service = createService().build();
User user = collection.findOneById(userid);
final OAuthRequest request = new OAuthRequest(Verb.POST, "https://api.github.com/user/repos", service);
Token token = new Token(user.getGithubToken(), "SECRET");
service.signRequest(token, request);
request.addHeader("Content-type", "application/vnd.github.v3+json");
request.addHeader("X-OAuth-Scopes", "repo");
request.addQuerystringParameter("name", "Test_v1");
LOGGER.info("Built request: " + request.getCompleteUrl());
final com.github.scribejava.core.model.Response response = request.send();
return Response.ok(response.getBody()).build();
}
The built URL looks like: https://api.github.com/user/repos?access_token=XXX_SECRET_XXX&name=Test_v1
I've also tried swapping the access_token after the params but same result.
Appreciate the any help.
Well I solved this by creating a object, serializing it, and adding it as a payload.
#POST
#Path("create_repo/{userId}/{projectId}")
#Produces(MediaType.APPLICATION_JSON)
public Response createRepo(#PathParam("userId") String userId, #PathParam("projectId") String projectId) {
// Setup collections
User user = userCollection.findOneById(userId);
ProjectDescription projectDescription = projectCollection.findOneById(projectId);
// Build repository object from project description
GithubRepository repository = new GithubRepository();
repository.setName(projectDescription.getTitle());
repository.setDescription(projectDescription.getDescription());
// Serialize object
ObjectMapper mapper = new ObjectMapper();
String jsonInString = null;
try {
jsonInString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(repository);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
// Build request
OAuthService service = createService().build();
final OAuthRequest request = new OAuthRequest(Verb.POST, PROTECTED_RESOURCE_URL + "/user/repos", service);
request.addHeader("content-type", "application/json");
request.addPayload(jsonInString);
// Sign and send request
Token token = new Token(user.getGithubToken(), "secret");
service.signRequest(token, request);
request.send();
return Response.status(201).build();
}
However, I'd still like to know where I went wrong with my first attempt.
Query string parameters are ignored in POST requests. That's why it worked when passing them in the request body.
From GitHub's API Overview docs:
Parameters
Many API methods take optional parameters. For GET requests, any parameters not specified as a segment in the path can be passed as an HTTP query string parameter:
curl -i "https://api.github.com/repos/vmg/redcarpet/issues?state=closed"
In this example, the ‘vmg’ and ‘redcarpet’ values are provided for the :owner and :repo parameters in the path while :state is passed in the query string.
For POST, PATCH, PUT, and DELETE requests, parameters not included in the URL should be encoded as JSON with a Content-Type of ‘application/json’:
$ curl -i -u username -d '{"scopes":["public_repo"]}' https://api.github.com/authorizations

Outlook OAuth2 access mails

I am following this post: Outlook RestGettingStarted. From my Java app I am trying to get AccessToken and RefreshToken. When I made Authorization code request, it ended into following error:
Sorry, but we’re having trouble signing you in. We received a bad
request.
Additional technical information: Correlation ID:
ed838d66-5f2e-4cfb-9223-a29082ecb26f Timestamp: 2015-08-20 10:20:09Z
AADSTS90011: The 'resource' request parameter is not supported.
NOTE: URL formation is correct as per documentation.
So, I removed "resource" query parameter from my code. And redirected authorize url in browser. On user consent I got authorization code. Using this code I got AccessToken. But when I try to connect with Outlook IMAP server it failed. Java ref Link for details: Java OAuth2
But it gives me error:
[AUTHENTICATIONFAILED] OAuth authentication failed.
NOTE: I added correct scope, and user email.
Then using obtained Access Token I made Mail Rest API call to get Messages from User Inbox. It ended into following error:
HTTP response:
{"error":{"code":"MailboxNotEnabledForRESTAPI","message":"REST API is
not yet supported for this mailbox."}}
Can anyone help me for following:
What is the exact cause for: "AADSTS90011: The 'resource' request parameter is not supported" after following Outlook dev docs.
How to resolve "MailboxNotEnabledForRESTAPI" error.
Is it possible to connect using java mail APIs to Outlook IMAP server with correct AccessToken ?
I ran into this recently, but don't remember which solved it. One main issue is in the documentation in that it is varying. It will tell you to attach "resource", but that is for something else like Azure.
Here is the code I used:
First request to send:
private static final String USER_OAUTH2_AUTHORIZE_URL = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
public String getOAuthDialog(Http.Request request) {
return USER_OAUTH2_AUTHORIZE_URL
+ "?client_id=" + config.getClientId()
+ "&redirect_uri=" + getOutlookLoginRedirect(request)
+ "&response_type=code"
+ "&scope=https%3A%2F%2Foutlook.office.com%2Fmail.send%20" +
"https%3A%2F%2Foutlook.office.com%2Fmail.readwrite%20" +
"offline_access%20openid%20email%20profile"
+ "&state=" + crypto.generateSignedToken();
}
Scope was the hardest thing to figure out. I found a lot of ones that did not work. And it wasn't clear that I needed to separate them with spaces.
Then they will send you a request to your redirect url that was supplied. It will contain a code which you need to exchange for the data you requested in the scope. The redirect url that is supplied needs to be the exact same. Also you need to register the redirect url on your application portal under the Platform->Add Platform->Redirect URI->Add Url
private static final String USER_ACCESS_TOKEN_URL = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
private Map<String, String> sendOutlookUserOAuthRequest(Http.Request request, String code) {
WSClient ws = WS.client();
HttpParameters params = new HttpParameters();
params.put("client_id", config.getClientId(), true);
params.put("client_secret", config.getClientSecret(), true);
params.put("code", code, true);
params.put("redirect_uri", getOutlookLoginRedirect(request), true);
params.put("grant_type", "authorization_code");
String postParams = OAuthUtil.parametersToString(params);
WSRequest wsRequest = ws.url(USER_ACCESS_TOKEN_URL)
.setMethod("POST")
.setContentType("application/x-www-form-urlencoded")
.setBody(postParams);
WSResponse wsResponse = wsRequest.execute().get(10, TimeUnit.SECONDS);
Map<String, String> result = new HashMap<>();
if (wsResponse.getStatus() != HttpStatus.SC_OK) {
return result;
}
JsonNode node = wsResponse.asJson();
if (node.hasNonNull("access_token")) {
result.put("access_token", node.get("access_token").asText());
}
if (node.hasNonNull("refresh_token")) {
result.put("refresh_token", node.get("refresh_token").asText());
}
if (node.hasNonNull("id_token")) {
String[] tokenSplit = node.get("id_token").asText().split("\\.");
if (tokenSplit.length >= 2) {
try {
JSONObject jsonObject = new JSONObject(new String(Base64.getDecoder().decode(tokenSplit[1])));
if (jsonObject.has("name")) {
result.put("name", jsonObject.get("name").toString());
}
if (jsonObject.has("email")) {
result.put("outlookUid", jsonObject.get("email").toString());
} else if (jsonObject.has("preferred_username")) {
result.put("outlookUid", jsonObject.get("preferred_username").toString());
}
} catch (JSONException e) {
log.error("Error extracting outlookUid from id_token: ", e);
}
}
}
return result;
}
Another request that you might need is to update the refresh token:
private String getAccessTokenFromRefreshToken(User user) {
WSClient ws = WS.client();
HttpParameters params = new HttpParameters();
params.put("client_id", config.getClientId(), true);
params.put("client_secret", config.getClientSecret(), true);
params.put("grant_type", "refresh_token");
params.put("refresh_token", user.getOutlookRefreshToken());
String postParams = OAuthUtil.parametersToString(params);
WSRequest wsRequest = ws.url(USER_ACCESS_TOKEN_URL)
.setMethod("POST")
.setContentType("application/x-www-form-urlencoded")
.setBody(postParams);
WSResponse wsResponse = wsRequest.execute().get(10, TimeUnit.SECONDS);
if (wsResponse.getStatus() != HttpStatus.SC_OK) {
log.error("Failure to refresh outlook access token for user: " + user +
". Received status: " + wsResponse.getStatus() + " : " + wsResponse.getStatusText());
return null;
}
JsonNode node = wsResponse.asJson();
if (node.hasNonNull("access_token")) {
String accessToken = node.get("access_token").asText();
return accessToken;
} else {
log.error("Outlook refresh token failure, 'access_token' not present in response body: " + wsResponse.getBody());
return null;
}
}
One issue I ran into that took far longer than I would have hoped was in getting the clientId and clientSecret. This was because the language microsoft uses wasn't the most explicit. Client Id and application id are used interchangeably. The client secret is also the password that you create on the Application Portal, not to be confused with the Private Key that you can generate.
So you actually want the application_id and the password, although they refer to them as client_id and client_secret with no direct indication as to the lines drawn.
This is all assuming you have set up an application on the Outlook Application Portal. https://apps.dev.microsoft.com/
I hope this helps, although I assume you probably already solved this.
I faced the same problem with Java mail. You need to add service principals for your application on the Azure AD.
Find complete steps explained in Medium article Complete guide: Java Mail IMAP OAuth2.0 Connect Outlook | by Ritik Sharma | Dec, 2022.

Categories