I was wondering if I can develop a Desktop App for LinkedIn using Java. I know it can be done as a web application easily, but a completely desktop application, is it possible?
I had a look at the linkedin api's and Java Wrapper for LinkedIn.
The code was explained for a web application. How do I manage that in a java desktop app, specifically the authorization part?
oAuth using Swing?
Please direct me in the right way.
After a very long time of testing with oAuth (with my own wrappers), I settled for Scribe which is a Java Wrapper for almost all oAuth mechanisms. To include Linkedin in a Desktop client, as Adam Trachtenberg (Thank you again) suggested, oob option was used, i.e., after logging in, a code generated by linkedin has to be entered in our Client so that it can be validated against the requested url. Hope this is useful for someone.
public class LinkedInExample
{
private static final String PROTECTED_RESOURCE_URL = "http://api.linkedin.com/v1/people/~/connections:(id,last-name)";
public static void main(String[] args) throws IOException
{
OAuthService service = new ServiceBuilder()
.provider(LinkedInApi.class)
.apiKey("YourApiKey")
.apiSecret("YourApiSecret")
.build();
Scanner in = new Scanner(System.in);
//BareBonesBrowserLaunch.openURL("www.google.com");
System.out.println("=== LinkedIn's OAuth Workflow ===");
System.out.println();
// Obtain the Request Token
System.out.println("Fetching the Request Token...");
Token requestToken = service.getRequestToken();
System.out.println("Got the Request Token!");
System.out.println();
System.out.println("Now go and authorize Scribe here:");
String authURL = service.getAuthorizationUrl(requestToken);
System.out.println(authURL);
BareBonesBrowserLaunch.openURL("www.google.com");
System.out.println("And paste the verifier here");
System.out.print(">>");
Verifier verifier = new Verifier(in.nextLine());
System.out.println();
// Trade the Request Token and Verfier for the Access Token
System.out.println("Trading the Request Token for an Access Token...");
Token accessToken = service.getAccessToken(requestToken, verifier);
System.out.println("Got the Access Token!");
System.out.println("(if your curious it looks like this: " + accessToken + " )");
System.out.println();
// Now let's go and ask for a protected resource!
System.out.println("Now we're going to access a protected resource...");
OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL);
service.signRequest(accessToken, request);
Response response = request.send();
System.out.println("Got it! Lets see what we found...");
System.out.println();
System.out.println(response.getBody());
System.out.println();
System.out.println("Thats it man! Go and build something awesome with Scribe! :)");
}
}
The BareBonesBrowserLaunch is used to launch the default browser with the Linkedin URL for the token request in most OS's. Since the Desktop part is not available in Java 1.5, the BareBonesBrowserLaunch solves the problem.
public class BareBonesBrowserLaunch {
static final String[] browsers = { "google-chrome", "firefox", "opera",
"epiphany", "konqueror", "conkeror", "midori", "kazehakase", "mozilla" };
static final String errMsg = "Error attempting to launch web browser";
public static void openURL(String url) {
try { //attempt to use Desktop library from JDK 1.6+
Class<?> d = Class.forName("java.awt.Desktop");
d.getDeclaredMethod("browse", new Class[] {java.net.URI.class}).invoke(
d.getDeclaredMethod("getDesktop").invoke(null),
new Object[] {java.net.URI.create(url)});
//above code mimicks: java.awt.Desktop.getDesktop().browse()
}
catch (Exception ignore) { //library not available or failed
String osName = System.getProperty("os.name");
try {
if (osName.startsWith("Mac OS")) {
Class.forName("com.apple.eio.FileManager").getDeclaredMethod(
"openURL", new Class[] {String.class}).invoke(null,
new Object[] {url});
}
else if (osName.startsWith("Windows"))
Runtime.getRuntime().exec(
"rundll32 url.dll,FileProtocolHandler " + url);
else { //assume Unix or Linux
String browser = null;
for (String b : browsers)
if (browser == null && Runtime.getRuntime().exec(new String[]
{"which", b}).getInputStream().read() != -1)
Runtime.getRuntime().exec(new String[] {browser = b, url});
if (browser == null)
throw new Exception(Arrays.toString(browsers));
}
}
catch (Exception e) {
JOptionPane.showMessageDialog(null, errMsg + "\n" + e.toString());
}
}
}
}
The LinkedInExample is taken mostly from this library - https://github.com/fernandezpablo85/scribe-java/downloads
Don't forget to include the Scribe jar and apache commons-codec (for Base64)
Yes you can it's all about playing with the API and utilizing the web services packed within the LinkedIn's API.
However, the entire process has to be implemented by using the HTTP requests etc and by parsing the response to render it on the JForm.
EDIT: Ahh! you are totally independent :-) thanks to XML..
If you can't figure out how to redirect the user to a web browser and have the browser redirect back to your application, check out the "out of bounds" (aka "oob") option for the OAuth callback. This will display a code to the member after they authorize your application, which they can type into your Java app.
Related
in my java SWING app, the user can transfer files to his DropBox space, I have successfully implemented the library and I'm trying to get the user's access token without having to copy and paste it into my app.
According to the documentation, I have to use HttpServletRequest to get what I want, but I get an exception, as written in the title.
public class LoginServlet implements HttpServletRequest {
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// read form fields
String token = request.getParameter("data-token");
// get response writer
PrintWriter writer = response.getWriter();
// build HTML code
String htmlRespone = "<html>";
htmlRespone += "<h2>token: " + token + "<br/>";
htmlRespone += "</html>";
// return response
writer.println(htmlRespone);
response.sendRedirect(Main.redirectUri);
}
#Override
public HttpSession getSession(boolean bln) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public HttpSession getSession() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
and in Main class
LoginServlet request = new LoginServlet();
// Fetch the session to verify our CSRF token
HttpSession session = request.getSession(true);
String sessionKey = "dropbox-auth-csrf-token";
DbxSessionStore csrfTokenStore = new DbxStandardSessionStore(session, sessionKey);
DbxRequestConfig config = new DbxRequestConfig("User"); //Client name can be whatever you like
DbxAppInfo appInfo = new DbxAppInfo(App key, App secret);
DbxWebAuth webAuth = new DbxWebAuth(config, appInfo);
DbxWebAuth.Request authRequest = DbxWebAuth.newRequestBuilder()
.withRedirectUri(redirectUri, csrfTokenStore)
.build();
String url = webAuth.authorize(authRequest);
Desktop.getDesktop().browse(new URL(url).toURI());
DbxAuthFinish authFinish;
try {
authFinish = webAuth.finishFromRedirect(redirectUri, csrfTokenStore, request.getParameterMap());
} catch (DbxWebAuth.BadRequestException ex) {
//log("On /dropbox-auth-finish: Bad request: " + ex.getMessage());
//response.sendError(400);
return;
} catch (DbxWebAuth.BadStateException ex) {
// Send them back to the start of the auth flow.
//response.sendRedirect(redirectUri);
return;
} catch (DbxWebAuth.CsrfException ex) {
//log("On /dropbox-auth-finish: CSRF mismatch: " + ex.getMessage());
//response.sendError(403, "Forbidden.");
return;
} catch (DbxWebAuth.NotApprovedException ex) {
// When Dropbox asked "Do you want to allow this app to access your
// Dropbox account?", the user clicked "No".
return;
} catch (DbxWebAuth.ProviderException ex) {
//log("On /dropbox-auth-finish: Auth failed: " + ex.getMessage());
//response.sendError(503, "Error communicating with Dropbox.");
return;
} catch (DbxException ex) {
//log("On /dropbox-auth-finish: Error getting token: " + ex.getMessage());
//response.sendError(503, "Error communicating with Dropbox.");
return;
}
String accessToken = authFinish.getAccessToken();
// Save the access token somewhere (probably in your database) so you
// don't need to send the user through the authorization process again.
// Now use the access token to make Dropbox API calls.
DbxClientV2 client = new DbxClientV2(config, accessToken);
//...
full stack
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:873)
Caused by: java.lang.UnsupportedOperationException: Not supported yet.
at cloud.LoginServlet.getSession(LoginServlet.java:404)
at cloud_new.Main.main(Main.java:103)
the row at cloud_new.Main.main(Main.java:103)
is this HttpSession session = request.getSession(true);
Note
This is not a solution for the main java question relate to some http error.
This is a proposed approach based or inspired in how heroku auth and google container registry auth works.
Also dropbox and other platforms does not offer a kind of special admin api_key to consume the final user resources. Due to that a web login in a real browser is required and this cannot be easily replaced or emulated with web_views or internal browsers in android or ios. Source
Basic idea
Develop a web application which exposes two functionalities: receive the redirect from dropbox authorization platform and a rest endpoint to query if user is authenticated.
Assumptions
web called my-oauth2-helper.com
Flow
user starts the desktop application.
desktop application queries to my-oauth2-helper.com/validate/auth sending user email.
my-oauth2-helper.com/validate/auth returns a field which indicate that user does not have a valid authentication and other field with the dropbox login url.
dropbox login url which has the classic oauth2 fields previously configured in dropbox developer console: client_id, redirect_uri, etc.
desktop application uses this login url to open a browser tab.
User is prompted with a valid dropbox web login, enter its credentials and accept the consent page.
Dropbox following the oauth2 protocol, redirects the user to a
my-oauth2-helper.com/redirect which is the classic field called redirect_uri
my-oauth2-helper.com/redirect receive the auth_code and exchange it for a valid access_token for this user and store it in a kind of database. After that could shows a message like: "Now, you can close this page and returns to the desktop application"
Since user was prompted with dropbox web login, the desktop application started to queries at regular intervals if user has a valid authentication to the endpoint my-oauth2-helper.com/token sending the email as request parameter
After valid access_token generation , the my-oauth2-helper.com/token endpoint returns a valid access_token for this user.
This access_token is ready to use in order to consume any dropbox api feature, which user accepted in consent page.
In our company we try to start using oauth2.0 with our Azure AD Tenant using vue.js as frontend and vert.x services on the backend.
The idea would be that i want to
If i call our vert.x service with the jwt which we got from Azure AD i got a runtime exception saying: "Not enough or too many segments". The JWT has 3 segments like expected. This is how i create the AzureADAuth:
OAuth2ClientOptions opts = new OAuth2ClientOptions();
opts.setFlow(OAuth2FlowType.AUTH_JWT);
OAuth2Auth auth = AzureADAuth.create(vertx,"{{application-id}}","{{secret}}","{{tenant-id}}", opts);
Inside my handler i try to authenticate:
HttpServerRequest request = context.request();
String authorization = request.headers().get(HttpHeaders.AUTHORIZATION);
String[] parts = authorization.split(" ");
scheme = parts[0];
token = parts[1];
JsonObject creds = new JsonObject();
creds.put("token_type", scheme);
creds.put("access_token", token);
authProvider.authenticate(creds,userAsyncResult -> {
if(userAsyncResult.succeeded()){
context.next();
} else {
context.fail(401);
}
});
So after i figured out that i need to add a jwk i tried to use the AzureADAuth.discover method.
My code looks like this:
OAuth2ClientOptions optsDisc = new OAuth2ClientOptions();
optsDisc.setSite("https://login.windows.net/{tenant-id}");
optsDisc.setClientID("{application-id}");
AzureADAuth.discover(vertx, optsDisc,res -> {
if (res.succeeded()) {
if(log.isDebugEnabled()) {
log.debug("Discover succeeded.");
}
} else {
log.error("Discover failed.");
}
});
Running this code causes a "Discover failed" with the following message:
java.lang.RuntimeException: java.security.cert.CertificateException: Could not parse certificate: java.io.IOException: Empty input
So my question is how do i authenticate my user with my given bearer token with vert.x?
I obviously had a version conflict here.
I set all my dependencies to 3.6.2 and now it works. Just took me a bit to figure out how to handle the discovery and that i don't need to create a new OAuth2Auth object with AzureAdAuth after the discovery.
For future reference:
OAuth2ClientOptions optsDisc = new OAuth2ClientOptions();
opts.setClientID("{client-id}");
AzureADAuth.discover(vertx, opts,res -> {
if (res.succeeded()) {
//use res.result() to access the through discovery already created OAuth2Auth Object
log.debug("Discover succeeded.");
} else {
log.error("Discover failed.");
}
})
We're using stormpath with Java & also trying to combine form Login with REST API authentication on the same application.
I've setup stormpath servlet plugin as described here https://docs.stormpath.com/java/servlet-plugin/quickstart.html... This works very fine.
Now, on the same application, we have APIs where I've implemented oAuth authentication with stormpath see here http://docs.stormpath.com/guides/api-key-management/
The first request for an access-token works fine by sending Basic Base64(keyId:keySecret) in the request header and grant_type = client_credentials in the body. Access tokens are being returned nicely. However trying to authenticate subsequent requests with the header Bearer <the-obtained-access-token> does not even hit the application before
returning the following json error message...
{
"error": "invalid_client",
"error_description": "access_token is invalid."
}
This is confusing because I've set breakpoints all over the application and I'm pretty sure that the API request doesn't hit the anywhere within the application before stormpath kicks in and returns this error. And even if stormpath somehow intercepts the request before getting to the REST interface, this message doesn't make any sense to me because i'm certainly making the subsequent API calls with a valid access-token obtained from the first call to get access-token.
I have run out of ideas why this could be happening but i'm suspecting that it may have something to do with stormpath config especially with a combination
of form Login/Authentication for web views and oAuth Athentication for REST endpoints. With that said, here's what my stormpath.properties looks like. Hope this could help point at anything I may be doing wrong.
stormpath.application.href=https://api.stormpath.com/v1/applications/[app-id]
stormpath.web.filters.authr=com.app.security.AuthorizationFilter
stormpath.web.request.event.listener = com.app.security.AuthenticationListener
stormpath.web.uris./resources/**=anon
stormpath.web.uris./assets/**=anon
stormpath.web.uris./v1.0/**=anon
stormpath.web.uris./** = authc,authr
stormpath.web.uris./**/**=authc,authr
Help with this would be highly appreciated.
The problem might be related to an incorrect request.
Is it possible for you to try this code in your app?:
private boolean verify(String accessToken) throws OauthAuthenticationException {
HttpRequest request = createRequestForOauth2AuthenticatedOperation(accessToken);
AccessTokenResult result = Applications.oauthRequestAuthenticator(application)
.authenticate(request);
System.out.println(result.getAccount().getEmail() + " was successfully verified, you can allow your protect operation to continue");
return true;
}
private HttpRequest createRequestForOauth2AuthenticatedOperation(String token) {
try {
Map<String, String[]> headers = new LinkedHashMap<String, String[]>();
headers.put("Accept", new String[]{"application/json"});
headers.put("Authorization", new String[]{"Bearer " + token});
HttpRequest request = HttpRequests.method(HttpMethod.GET)
.headers(headers)
.build();
return request;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
I've prepared an example that demonstrates oauth token creation as well as authorized access to protected pages using access tokens.
It builds off of the servlet example in the Stormpath SDK. The repo can be found here: https://github.com/stormpath/stormpath-java-oauth-servlet-sample
It demonstrates running a servlet application and having an out-of-band program get and use oauth tokens to access protected resources.
The core of the oauth part is in TokenAuthTest.java:
public class TokenAuthTest {
public static void main(String[] args) throws Exception {
String command = System.getProperty("command");
if (command == null || !("getToken".equals(command) || "getPage".equals(command))) {
System.err.println("Must supply a command:");
System.err.println("\t-Dcommand=getToken OR");
System.err.println("\t-Dcommand=getPage OR");
System.exit(1);
}
if ("getToken".equals(command)) {
getToken();
} else {
getPage();
}
}
private static final String APP_URL = "http://localhost:8080";
private static final String OAUTH_URI = "/oauth/token";
private static final String PROTECTED_URI = "/dashboard";
private static void getToken() throws Exception {
String username = System.getProperty("username");
String password = System.getProperty("password");
if (username == null || password == null) {
System.err.println("Must supply -Dusername=<username> -Dpassword=<password> on the command line");
System.exit(1);
}
PostMethod method = new PostMethod(APP_URL + OAUTH_URI);
method.setRequestHeader("Origin", APP_URL);
method.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
method.addParameter("grant_type", "password");
method.addParameter("username", username);
method.addParameter("password", password);
HttpClient client = new HttpClient();
client.executeMethod(method);
BufferedReader br = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream()));
String readLine;
while(((readLine = br.readLine()) != null)) {
System.out.println(readLine);
}
}
private static void getPage() throws Exception {
String token = System.getProperty("token");
if (token == null) {
System.err.println("Must supply -Dtoken=<access token> on the command line");
System.exit(1);
}
GetMethod method = new GetMethod(APP_URL + PROTECTED_URI);
HttpClient client = new HttpClient();
System.out.println("Attempting to retrieve " + PROTECTED_URI + " without token...");
int returnCode = client.executeMethod(method);
System.out.println("return code: " + returnCode);
System.out.println();
System.out.println("Attempting to retrieve " + PROTECTED_URI + " with token...");
method.addRequestHeader("Authorization", "Bearer " + token);
returnCode = client.executeMethod(method);
System.out.println("return code: " + returnCode);
}
}
i have just listing down the circle name in my google+domain api but getting an error of
i have used installed application-> other option while making the application in google developer console
I am developing a small installed application wherein I am integrating with Google+ Domain API's. I am using OAuth2 authentication.I have generated client_id and client_secret for my Installed application from Google API console. Using Google+ Domain API's, I am able to generate the access token.
Also I am using ---some----#gmail.com using gmail account
my code is as :-
enter code here
private static final String CLIENT_ID = "xyxxxxxxxx something in there";
private static final String CLIENT_SECRET = "Fhh1LYQ__UTso48snXHyqSQ2";
public static void main(String[] args) throws IOException {
// List the scopes your app requires:
try{
List<String> SCOPE = Arrays.asList(
"https://www.googleapis.com/auth/plus.me",
"https://www.googleapis.com/auth/plus.stream.write",
"https://www.googleapis.com/auth/plus.circles.read");
final String REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob";
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
new NetHttpTransport(),
new JacksonFactory(),
CLIENT_ID, // This comes from your Developers Console project
CLIENT_SECRET, // This, as well
SCOPE)
.setApprovalPrompt("force")
// Set the access type to offline so that the token can be refreshed.
// By default, the library will automatically refresh tokens when it
// can, but this can be turned off by setting
// dfp.api.refreshOAuth2Token=false in your ads.properties file.
.setAccessType("offline").build();
// This command-line se`enter code here`rver-side flow example requires the user to open the
// authentication URL in their browser to complete the process. In most
// cases, your app will use a browser-based server-side flow and your
// user will not need to copy and paste the authorization code. In this
// type of app, you would be able to skip the next 5 lines.
// You can also look at the client-side and one-time-code flows for other
// options at https://developers.google.com/+/web/signin/
String url = flow.newAuthorizationUrl().setRedirectUri(REDIRECT_URI).build();
System.out.println("Please open the following URL in your browser then " +
"type the authorization code:");
System.out.println(" " + url);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String code = br.readLine();
// End of command line prompt for the authorization code.
GoogleTokenResponse tokenResponse = flow.newTokenRequest(code)
.setRedirectUri(REDIRECT_URI).execute();
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(new NetHttpTransport())
.setJsonFactory(new JacksonFactory())
.setClientSecrets(CLIENT_ID, CLIENT_SECRET)
.addRefreshListener(new CredentialRefreshListener() {
#Override
public void onTokenResponse(Credential credential, TokenResponse tokenResponse) {
// Handle success.
System.out.println("Credential was refreshed successfully.");
}
#Override
public void onTokenErrorResponse(Credential credential,
TokenErrorResponse tokenErrorResponse) {
// Handle error.
System.err.println("Credential was not refreshed successfully. "
+ "Redirect to error page or login screen.");
}
})
// You can also add a credential store listener to have credentials
// stored automatically.
//.addRefreshListener(new CredentialStoreRefreshListener(userId, credentialStore))
.build();
// Set authorized credentials.
credential.setFromTokenResponse(tokenResponse);
// Though not necessary when first created, you can manually refresh the
// token, which is needed after 60 minutes.
credential.refreshToken();
// Create a new authorized API client
PlusDomains service = new PlusDomains.Builder(new NetHttpTransport(), new JacksonFactory(), credential).setApplicationName("Get-me").setRootUrl("https://www.googleapis.com/").build();
PlusDomains.Circles.List listCircles = service.circles().list("me");
listCircles.setMaxResults(5L);
CircleFeed circleFeed = listCircles.execute();
List<Circle> circles = circleFeed.getItems();
// Loop until no additional pages of results are available.
while (circles != null) {
for (Circle circle : circles) {
System.out.println(circle.getDisplayName());
}
// When the next page token is null, there are no additional pages of
// results. If this is the case, break.
if (circleFeed.getNextPageToken() != null) {
// Prepare the next page of results
listCircles.setPageToken(circleFeed.getNextPageToken());
// Execute and process the next page request
circleFeed = listCircles.execute();
circles = circleFeed.getItems();
} else {
circles = null;
}
}
}catch(Exception e)
{
System.out.println("Exception "+e);
}
}
Its an INSTAlled Application -> other Options........ in google developer console
i get the below error:---
Exception com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "global",
"message" : "Forbidden",
"reason" : "forbidden"
} ],
"message" : "Forbidden"
}
Note: I have also enabled Google+ Domain API in my Google API Console.
REDIRECT_URI ="urn:ietf:wg:oauth:2.0:oob" since it's a Installed app. Any Suggestions?
Please help me out guys
See this other answer: the Google+ Domains API is only "for people who use Google Apps at college, at work, or at home." It appears that Google does not currently allow apps to list circles for regular Google+ accounts.
I am trying to create a simple app on the app engine where users log
in through their Google account, and then it adds an event to their
calendar.
And I am using Java along with Eclipse for this. I have found a simple
code online:
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// Create an instance of GoogleOAuthParameters
GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);
oauthParameters.setScope("http://docs.google.com/feeds/");
GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(
new OAuthHmacSha1Signer());
// Remember the token secret that we stashed? Let's get it back
// now. We need to add it to oauthParameters
String oauthTokenSecret = (String) req.getSession().getAttribute(
"oauthTokenSecret");
oauthParameters.setOAuthTokenSecret(oauthTokenSecret);
// The query string should contain the oauth token, so we can just
// pass the query string to our helper object to correctly
// parse and add the parameters to our instance of oauthParameters
oauthHelper.getOAuthParametersFromCallback(req.getQueryString(),
oauthParameters);
try {
// Now that we have all the OAuth parameters we need, we can
// generate an access token and access token secret. These
// are the values we want to keep around, as they are
// valid for all API calls in the future until a user revokes
// our access.
String accessToken = oauthHelper.getAccessToken(oauthParameters);
String accessTokenSecret = oauthParameters.getOAuthTokenSecret();
// In a real application, we want to redirect the user to a new
// servlet that makes API calls. For the safe of clarity and simplicity,
// we'll just reuse this servlet for making API calls.
oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);
// This is interesting: we set the OAuth token and the token secret
// to the values extracted by oauthHelper earlier. These values are
// already in scope in this example code, but they can be populated
// from reading from the datastore or some other persistence mechanism.
oauthParameters.setOAuthToken(accessToken);
oauthParameters.setOAuthTokenSecret(accessTokenSecret);
oauthParameters.setOAuthCallback("http://www.facebook.com");
oauthHelper.getUnauthorizedRequestToken(oauthParameters);
// Create an instance of the DocsService to make API calls
DocsService client = new DocsService("Malware Inc.");
// Use our newly built oauthParameters
client.setOAuthCredentials(oauthParameters, new OAuthHmacSha1Signer());
URL feedUrl = new URL("https://docs.google.com/feeds/default/private/full");
DocumentListFeed resultFeed = client.getFeed(feedUrl,
DocumentListFeed.class);
for (DocumentListEntry entry : resultFeed.getEntries()) {
resp.getWriter().println(entry.getTitle().getPlainText());
}
} catch (OAuthException e) {
// Something went wrong. Usually, you'll end up here if we have invalid
// oauth tokens
resp.getWriter().println("Here is the problem");
//Server shows 500 problem
} catch (ServiceException e) {
// Handle this exception
}
}
I have registered my application and added the KEY and Secret above
the function, but when I deploy it to the app engine it gives a 500
server error.
Could someone post a simple java program that uses gdata and oauth to
log in a Google user and print the contacts on the screen?
Thanks.
-Manoj
I was facing the same problem, and it took me a while to figure it out.
Actually, the problem is that your are missing some parts in the OAuth authorization process.
As you may know, it a 3-legged process:
Get an unauthorized request token
Authorize the request token
Exchange the authorized request token for an access token and make calls to Google Data with it.
In your case, you are doing step 3 directly.
So before you can call the servlet you described above, and effectively retrieve user's Google Data,
the user must have grant access to your application, by browsing to an authorization URL from his web browser.
You need a first servlet , for example accessible at http://yourapp.com/RequestAccess
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(YOUR_CONSUMER_KEY);
oauthParameters.setOAuthConsumerSecret(YOUR_CONSUMER_SECRET);
OAuthHmacSha1Signer signer = new OAuthHmacSha1Signer();
GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(signer);
oauthParameters.setScope(FEED_SCOPE);
try {
oauthHelper.getUnauthorizedRequestToken(oauthParameters);
//GET THE UNAUTHORIZED TOKENS
String oauthRequestToken = oauthParameters.getOAuthToken();
String oauthTokenSecret = oauthParameters.getOAuthTokenSecret();
//SAVE THEM SOMEWEHERE (FOR EXAMPLE IN THE SESSION LIKE YOU DID)
// ....
//GET THE AUHTORIZATION URL
String authorizationURL= oauthHelper.createUserAuthorizationUrl(oauthParameters);
// YOU NOW HAVE THE AUHTORIZATION URL, SEND IT BACK TO THE USER SOMEHOW
// ( FOR EXAMPLE BY REDIRECTING THE REQUEST TO THAT URL)
// ...
} catch (OAuthException e1) {
LOGGER.error("error while getting unauthorized request token '{}' ", e1);
}
}
Once the user has navigate to that URL, and grant acces, you can now call your second servlet and it should work.
More info can be found on Google OAuth page here
Hope it helps!