Unable to authenticate with Google Tasks - Homework - java

This week I had a small program to develop, I needed to create a Web Application(using a Java Servlet on localhost), this Web App is required to do the following:
Obtain and show issues from public organizations from GitHub
Obtain authentication thru OpenID Connect(OAuth 2.0)
Create a Google Task on the default tasklist from an issue using REST
Note: I can only use HTTP, no jar libs
The first part was easy, just had to make the request to the GitHub API and parse the JSON, no problem here
The second part was somewhat easy, I had to create a new Client ID in Google Developer Console, where I'd set the callback and receive the code on it, I'll put it here just in case I'm doing something wrong with it:
Login.java
...
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
System.out.println("--New login request was received --");
resp.setStatus(302);
resp.setHeader("Location", GoogleStuff.AUTH_LINK);
}
...
callback.java
...
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
Cookie c = new Cookie("googleCode", req.getParameter("code")); c.setMaxAge(60*60); //1 Hour
//Example code received from Google
//4/6POIUYwZA3tFCnX_2feRDGiPMQOU7At8HyfOzemMkOY.wtiPpsElo8wZoiIBeR5Q2m9sqEaFkwI
resp.addCookie(c);
resp.setStatus(302);
resp.setHeader("Location","searchOrg");
}
...
My problem comes on the third part, I get the response code 401(Not Authorized) from Google, I'm sure I'm doing something wrong, but I don't really know what is wrong. This is probably all wrong, so bear with it :p
Note: To get the API Key I used the Google Developer Console and created a key for Browsers
GoogleStuff.java
...
public static String AUTH_LINK = "https://accounts.google.com/o/oauth2/auth?"+
"scope=https://www.googleapis.com/auth/tasks&"+
"redirect_uri=http://localhost:5005/callback&"+
"response_type=code&" +
"client_id=" + FirstHttpServer.CLIENT_ID +
"&approval_prompt=force";
...
public static void addTask(Issue i, String googleCode){
try {
String postURL = "https://www.googleapis.com/tasks/v1/lists/%40default/tasks?key=" + MyServer.API_KEY;
URL url = new URL(postURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Authorization", googleCode);
BufferedWriter httpRequestBodyWriter = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream()));
httpRequestBodyWriter.write(i.toJson());
httpRequestBodyWriter.close();
Scanner httpResponseScanner = new Scanner(connection.getInputStream());
while(httpResponseScanner.hasNextLine())
System.out.println(httpResponseScanner.nextLine());
httpResponseScanner.close();
} catch (IOException e) {
System.out.println(e.toString());
throw new RuntimeException();
}
I've been at it for a couple days, but with other projects also tightening my time, its becoming increasingly hard for me to find the problem with this, which is why I request your help :)
Thanks in advance

An API will indicate that an access token has expired when it returns a 401 status code.To obtain a new access token, make a request to the token endpoint and include the client_id, client_secret, refresh_token, and grant_type parameters.
You can find more information in this link.
Hope that helps!

Related

Very simple example for Spring OAuth2 [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 5 years ago.
Improve this question
I'm struggling with Spring OAuth2. All I want to do is very simple, and I don't know where to start. All examples I found are never the same ones and I'm totally lost.
I have a login form, with username and password. When I submit the form, I want to
Connect to an ldap server to check if the user exists (that part is done)
If the user exists, I want to get an access token with OAuth2 to allow that user to access our API
Send the following response to the client : {"username": "john doe", "access_token":"my_token"}
It seems very trivial, but although I read a lot of documentation about OAuth2, I can't find the way to do it with Spring OAuth2. As a start, I used that tutorial :Implementing OAuth2 with Spring Security but it focuses only on server configuration, and provides no source code for the client.
Could someone provide me an example of source code ?
Thanks for your help
Ok, this is a two parts authentication.
First you will do a HTTP Get in order to get the code. So the client will be redirected to the authentication server.
Once he enters login/ passwords and successfully authenticate to the Oauth2 app he will be redirected back to his client app with the code added as a parameter in the URL.
The client gets the code from the URL and calls back the authentication server with a HTTP POST with the code as request parameter and he will get the access token in the response the access token is then used as a header to access the
The implementation of this process will depend on the client side technology you will use.
Here is an example of a third party Servlet that calls the Oauth2 application :
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
{
final HttpSession session = request.getSession();
final String code = Strings.nullToEmpty(request.getParameter("code"));
if (!code.isEmpty()) {
this.getAccessToken(response, session, code);
} else {
this.getOAuth2AuthorizationUrl(response, session);
}
}
1 - First, we make the call to the servlet without the code parameter to call the method that will redirect us to the authentication server:
private void getOAuth2AuthorizationUrl(HttpServletResponse response, HttpSession session)
{
final String oauth2AuthorizationUrl = "http://localhost:8080/oauth/authorize?" +
+ "response_type=code"
+ "&client_id=client-with-registered-redirect"
+ "&redirect_url=http://client_host?key=value"
+ "&scope=read"
try {
final PrintWriter writer = response.getWriter();
writer.write(oauth2AuthorizationUrl);
writer.flush();
} catch (IOException e) {
log.error("IO Exception : {}", e.getMessage());
}
}
2 - Once we get the code we post a request to get the access token :
private void getAccessToken(HttpServletResponse response, final HttpSession session, final String code)
{
HttpClient httpClient = new HttpClient();
PostMethod accessTokenRequest = new PostMethod(accessTokenEndpoint);
AccessToken var8;
try {
accessTokenRequest.addRequestHeader(new Header("Authorization", "Basic " + "http://localhost:8080/oauth/token"));
accessTokenRequest.addRequestHeader(new Header("Accept", "application/json"));
NameValuePair[] params = new NameValuePair[] { new NameValuePair("code", code),
new NameValuePair("grant_type", "authorization_code"),
new NameValuePair("redirect_uri", " your redirect uri"), new NameValuePair("client_id", "your client id") };
accessTokenRequest.setQueryString(EncodingUtil.formUrlEncode(params, UTF_8.displayName()));
httpClient.executeMethod(accessTokenRequest);
if (accessTokenRequest.getStatusCode() != 200) {
this.toException(accessTokenRequest);
return null;
}
// JSON response Object AccessToken
AccessToken accessToken = (AccessToken) PARSER.readValue(accessTokenRequest.getResponseBodyAsStream(),
AccessToken.class);
final PrintWriter writer = response.getWriter();
writer.append(accessToken.getTokenString);
writer.flush();
} catch (IOException e) {
log.error("IO Exception : {}", e.getMessage());
}
finally {
accessTokenRequest.releaseConnection();
}
}
You can get your access token on the HTTP Response on the client side and use it to access resources.

Cannot find a handler for POST with boundary

I'm in the midst of testing my application which is using an HTTP-server. Instead of mocking I decided to go with a HTTP server fixture. Meaning that I do not have to mock any productional code. To accomplish this goal I currently chose for a free to use 3rd party library fixd.
I was able to successfully create several unit tests - which are working by means of a GET request. Most are quite simple, i.e.:
#Test
public void verifyConnectionTest()
{
try
{
final String body = FileUtils.readFileToString(RESOURCE);
final String path = "/";
this.server.handle(Method.GET, path).with(
new HttpRequestHandler() {
#Override
public void handle(final HttpRequest request,
final HttpResponse response)
{
response.setStatusCode(200);
response.setContentType("text/xml");
response.setBody(body);
}
});
// Setting up my HTTP client
// Execute some tasks
// asserting of everything was valid
}
catch (final IOException e)
{
fail(e.getMessage());
}
}
But I now have to send a POST request with multipart/form-data. Which does not make much of a difference other than changing the method and content-type:
#Test
public void executeStepTest()
{
try
{
final String body = FileUtils.readFileToString(SERVICE_RESPONSE);
final String path = "/";
this.server.handle(Method.POST, path, "multipart/form-data").with(
new HttpRequestHandler() {
#Override
public void handle(final HttpRequest request,
final HttpResponse response)
{
response.setStatusCode(200);
response.setContentType("text/xml");
response.setBody(body);
}
});
// Setting up my HTTP client
// Execute some tasks
// asserting of everything was valid
}
catch (final IOException e)
{
fail(e.getMessage());
}
}
However I get the following error: [ERROR] could not find a handler for POST - / - multipart/form-data; boundary=bqCBI7t-VW1xaJW7BADmTiGMg9w_YM2sHH8ukJYx and my guess is that fixd doesn't recognize the boundary-party. Since the documentation does not show an example I'm quite stuck on this part.
I tried using some wildcards such as '*', no succes. Thus; I need a way to either tell fixd to accept that boundary or use some wildcards I didn't yet discover. Any help would be great, thanks!
I've been making some debug and it seems to be that the problem is in the fixd core.
Basically, fixd indexes every RequestHandlerImpl by a HandlerKey (which includes ContentType as part of the key) in the map handlerMap. See method org.bigtesting.fixd.core.FixtureContainer#resolve.
...
HandlerKey key = new HandlerKey(method, route, contentType);
RequestHandlerImpl handler = handlerMap.get(key);
if (handler == null) {
// Error
}
...
Problem: When the request is multipart/form-data, boundary data (which it's generated dinamically every request) is part of the content type. So, any handler is found in handlerMap because the key changes with every running.
I've made a little test only to check that this is the cause of the problem, passing the contentType to fixd server.handle after the creation of the multipart request, and it works fine.
See the test below:
#Test
public void verifyConnectionTest_multipart() {
try {
// 1. Create multipart request (example with http-commons 3.1)
PostMethod filePost = new PostMethod(url);
Part[] parts = { new StringPart("param", "value") };
MultipartRequestEntity request = new MultipartRequestEntity(parts, filePost.getParams());
filePost.setRequestEntity(request);
// 2. fixd server handle (passing the request content type)
this.server.handle(Method.POST, "/", request.getContentType()).with(
new HttpRequestHandler() {
#Override
public void handle(final HttpRequest request,
final HttpResponse response) {
response.setStatusCode(200);
response.setContentType("text/xml");
}
});
// 3. Execute multipart request
HttpClient client = new HttpClient();
int status = client.executeMethod(filePost);
// 4. Assertions
Assert.assertEquals(200, status);
} catch (Exception e) {
Assert.fail(e.getMessage());
}
}
Hope it helps you to clarify the problem. Cheers
This was a bug in fixd, and has been fixed in version 1.0.3. Your original code should work using this new version of fixd.

Getting a ConnectionClosedException with Http.Core talking to Http.Client 4?

I am trying my hand at using http.core & client 4.3. In general it works well, and is quite pleasant to deal with. However, I am getting a ConnectionClosedException on one of my transfers and I can't see why. Others work just fine as far as I can tell.
Everything follows the examples in a pretty straight forward way. If it didn't, it was re-written to as much as possible in an effort to get rid of this.
There are 2 servers, both running the same code [A & B]
A HttpClient sends a request "AX" (POST) to B
B HttpService receives the "AX" post, processes it
B HttpClient sends a reply "BR" (POST) to A on a different port
Later This should happen after the connection to A is closed, or as close as possible
Right now the code doesn't actually care
A receives the reply from B (on a different thread) and does things
In the problem scenario, A is running as the server, and B is sending a POST. Sorry it isn't always clear, since in one transaction both sides end up running server and client code.
A Sends POST to B:8080. Get back a proper response inline, everything ok.
POST Connection to B:8080 gets closed properly
B sends new POST (like an ACK) to A (ex... B:53991 => A:9000).
A Processs everything. No issues
A rasies ConnectionClosedException
Since I don't why it's happening for sure, I tried to put everything I think is relevant in there. My only thought right now is that it has something to with making sure I add/change connection control headers, but I can't see how that would affect anything.
Stack Trace from machine "A", when the reply from B comes
org.apache.http.ConnectionClosedException: Client closed connection
at org.apache.http.impl.io.DefaultHttpRequestParser.parseHead(DefaultHttpRequestParser.java:133)
at org.apache.http.impl.io.DefaultHttpRequestParser.parseHead(DefaultHttpRequestParser.java:54)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:260)
at org.apache.http.impl.DefaultBHttpServerConnection.receiveRequestHeader(DefaultBHttpServerConnection.java:131)
at org.apache.http.protocol.HttpService.handleRequest(HttpService.java:307)
at com.me.HttpRequestHandlerThread.processConnection(HttpRequestHandlerThread.java:45)
at com.me.net.http.HttpRequestHandlerThread.run(HttpRequestHandlerThread.java:70)
com.me.ExceptionHolder: Client closed connection
at com.me.log.Log.logIdiocy(Log.java:77)
at com.me.log.Log.error(Log.java:54)
at com.me.net.http.HttpRequestHandlerThread.run(HttpRequestHandlerThread.java:72)
Caused by: org.apache.http.ConnectionClosedException: Client closed connection
at org.apache.http.impl.io.DefaultHttpRequestParser.parseHead(DefaultHttpRequestParser.java:133)
at org.apache.http.impl.io.DefaultHttpRequestParser.parseHead(DefaultHttpRequestParser.java:54)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:260)
at org.apache.http.impl.DefaultBHttpServerConnection.receiveRequestHeader(DefaultBHttpServerConnection.java:131)
at org.apache.http.protocol.HttpService.handleRequest(HttpService.java:307)
at com.me.net.http.HttpRequestHandlerThread.processConnection(HttpRequestHandlerThread.java:45)
at com.me.net.http.HttpRequestHandlerThread.run(HttpRequestHandlerThread.java:70)
This is the code running on B, the "client" in this scenario. It is trying to POST the reply acknowledging that the first POST from A was received properly. There really isn't much to transmit, and the response should only be an HTTP 200:
try (CloseableHttpClient client = HttpClients.createDefault()) {
final HttpPost post = new HttpPost(url);
post.setHeaders(/* create application specific headers */);
ByteArrayEntity entity = new ByteArrayEntity(IOUtils.toByteArray(myStream));
post.setEntity(entity);
ResponseHandler<Void> responseHandler = new ResponseHandler<Void>() {
#Override
public Void handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
StatusLine status = response.getStatusLine();
if (!NetUtil.isValidResponseCode(response)) {
throw new ClientProtocolException("Unexpected Error! Oops");
}
// consume the response, if there is one, so the connection will close properly
EntityUtils.consumeQuietly(response.getEntity());
return null;
}
};
try {
client.execute(post, responseHandler);
} catch (ClientProtocolException ex) {
// logic to queue a resend for 10 minutes later. not triggered
throw ex;
}
}
On A: This is called async because the response doesn't come in over the same http connection.
The main request handler does a lot more work, but it is amazing how little code there is actually controlling the HTTP in the handler/server side. Great library... that I am misusing somehow. This is the actual handler, with everything simplified a bit, validation removed, etc.
public class AsyncReceiverHandler implements HttpRequestHandler {
#Override
public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException {
// error if not post, other logic. not touching http. no errors
DefaultBHttpServerConnection connection = (DefaultBHttpServerConnection) context.getAttribute("connection");
Package pkg = NetUtil.createPackageFrom(connection); // just reads sender ip/port
NetUtil.copyHttpHeaders(request, pkg);
try {
switch (recieive(request, pkg)) {
case EH_OK:
response.setStatusCode(HttpStatus.SC_OK);
break;
case OHNOES_BAD_INPUT:
response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
response.setEntity(new StringEntity("No MDN entity found in request body"));
// bunch of other cases, but are not triggered. xfer was a-ok
}
} catch (Exception ex) {
//log
}
}
private MyStatus receiveMdn(HttpRequest request, Package pkg) throws Exceptions..., IOException {
// validate request, get entity, make package, no issues
HttpEntity resEntity = ((HttpEntityEnclosingRequest) request).getEntity();
try {
byte[] data = EntityUtils.toByteArray(resEntity);
// package processing logic, validation, fairly quick, no errors thrown
} catch (Exceptions... ex) {
throw ExceptionHolder(ex);
}
}
}
This is the request handler thread. This and the server are taken pretty much verbatim from the samples. The service handler just starts the service and accept()s the socket. When it gets one, it creates a new copy of this, and calls start():
public HttpRequestHandlerThread(final HttpService httpService, final HttpServerConnection conn, HttpReceiverModule ownerModule) {
super();
this.httpService = httpService;
this.conn = (DefaultBHttpServerConnection) conn;
}
private void processConnection() throws IOException, HttpException {
while (!Thread.interrupted() && this.conn.isOpen()) {
/* have the service create a handler and pass it the processed request/response/context */
HttpContext context = new BasicHttpContext(null);
this.httpService.handleRequest(this.conn, context);
}
}
#Override
public void run() {
// just runs the main logic and reports exceptions.
try {
processConnection();
} catch (ConnectionClosedException ignored) {
// logs error here (and others).
} finally {
try { this.conn.shutdown(); } catch (IOException ignored) {}
}
}
}
Well, this seems stupid now, and really obvious. I ignored the issue for a while and moved on to other things, and the answer bubbled up from the subconscious, as they will.
I added this header back and it all cleared up:
post.setHeader("Connection", "close, TE")
Somehow the line to set the Connection header got removed, probably accidentally by me. A lot of them get set, and it was still there, just wrong in this code path. Basically, the server expects this connection to close immediately but the header was reverting to the default keep-alive. Since the client closes the connection as soon as it is done with it this was surprising the server, who was told otherwise, and rightly compliained :D In the reverse path everything was OK.
Since I had just changed the old stack to use HttpComponents I didn't look at headers and such, and I just assumed I was using it wrong. The old stack didn't mind it.

Proper Form of API request to Blogger using Java/App Engine -error 401

I am running into issue in forming the correct api statement for JAVA in calling the Blogger API.
I have tested my statement via the Google Cloud Console and it works but does not work in my code. I am using Google App Engine and have been authorized to use Blogger. The authorization is also tied to the account running Google App Engine.
Any ideas would be helpfull.. have tried many things over the weekend.
Thanks
Request
GET https://www.googleapis.com/blogger/v3/blogs/7676001971884966148/posts?key= {YOUR_API_KEY}
Authorization: Bearer ya29.1.AADtN_Vd7lKj8Xy3KbZ1veJjjjv712Nc1erLY2dmAK3gorNilVd0652vnqrrovfuLfSKkQ
X-JavaScript-User-Agent: Google APIs Explorer
Response
200 OK
- Show headers -
{
"kind": "blogger#postList",
"nextPageToken": "CgkIChjim-ftqygQhIKb6_zjqMNq",
"items": [
{
etc.....
My Code
public class BloggerHandler
{
public static final Logger log = Logger.getLogger(BloggerHandler.class.getName());
public void testCreds() throws Exception {
try{
ArrayList<String> scopes = new ArrayList<String>();
scopes.add("https://www.googleapis.com/auth/blogger");
scopes.add("https://www.googleapis.com/auth/blogger.readonly");
AppIdentityService appIdentity = AppIdentityServiceFactory.getAppIdentityService();
AppIdentityService.GetAccessTokenResult accessToken = appIdentity.getAccessToken(scopes);
// The token asserts the identity reported by appIdentity.getServiceAccountName()
JSONObject request = new JSONObject();
//request.put("maxPosts", "1");
//request.put("view", "AUTHOR");
log.info("request!!!" + request);
URL url = new URL("https://www.googleapis.com/blogger/v3/blogs/7676001971884966148/posts?");
log.info("URL:" + url);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("GET");
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Authorization", "OAuth" + accessToken.getAccessToken());
log.info("Con!!" + connection);
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
request.write(writer);
writer.close();
log.info("connection:" + connection.getResponseCode());
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
// Note: Should check the content-encoding.
JSONTokener response_tokens = new JSONTokener(connection.getInputStream());
JSONObject response = new JSONObject(response_tokens);
log.info("resp:" + response.get("title"));
} // end if
else {
throw new Exception();
}// end else
} // end try
catch (Exception e) {
// Error handling elided.
log.info("ex:" + e);
}
// end catch
}// end void
}// end class
After a few long nights I was able to figure out how to access the Google Blogger API from a GAE project.
There are a couple of key things that I did that may help aid you.
In your Google Appe Engine project make sure that it is linked to the Google API Console. IN the GAE Admin project screen you should see a Google APIs Console Project Number:XX
In the Google API Cloud console make sure you are authorized for Blogger (or whatever cloud API you want to use). Create a project (website.. etc) and copy down the API string that it gives you.
Once you have that API string the code below should get you started with base connection.
The code below should return a "200" connection with the stats of the current blog you are trying to reach. From here you can expand upon the API.
// On a side note I know there is a way to read the API from Google Cloud so it does not have to be part of the code. Still working on that workflow.
import java.util.logging.Logger;
import java.util.Arrays;
import com.google.api.client.googleapis.extensions.appengine.auth.oauth2.AppIdentityCredential;
import com.google.api.services.blogger.Blogger;
import com.google.api.services.blogger.Blogger.Blogs.GetByUrl;
import com.google.api.services.blogger.Blogger.Posts.List;
import com.google.api.services.blogger.BloggerScopes;
import com.google.api.services.blogger.model.Blog;
import com.google.api.services.blogger.model.Post;
import com.google.api.services.blogger.model.PostList;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.extensions.appengine.http.UrlFetchTransport;
import java.io.IOException;
public class BlogHandler
{
public Blogger blogger = null;
public Blog blog;
public java.util.List<Post> posts;
public static final Logger log = Logger.getLogger(EngineParseFeed.class.getName());
static final String API_KEY = "{Your GOOGLE CLOUD API}";
public BlogHandler() {}
public void setupService () throws IOException {
AppIdentityCredential credential = null;
credential = new AppIdentityCredential(Arrays.asList(BloggerScopes.BLOGGER)); // Add your scopes here
this.blogger = new Blogger.Builder(new UrlFetchTransport(), new JacksonFactory(), credential).setApplicationName("trivalAPPName").build();
}
public void executeGetBlogByUrl (String url) throws IOException {
GetByUrl request = blogger.blogs().getByUrl( url );
this.blog = request.setKey(API_KEY).execute();
log.info ("Blog" + this.blog);
}
I managed to get the Blogger API working properly on Google App Engine by using two servlets and modelling them after the examples on this page: https://developers.google.com/google-apps/tasks/oauth-authorization-callback-handler. The example code is out of date and uses some kind of deprecated draft10 library.
Here's the working version for the servlet that posts to Blogger:
public class BloggerServlet
{
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
public static GoogleAuthorizationCodeFlow flow;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
{
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Entity OAuthTokenEntity;
OAuthProperties oauthProperties = new OAuthProperties();
String OAuthAccessToken, OAuthRefreshToken;
try
{
OAuthTokenEntity = datastore.get(KeyFactory.createKey("OAuthTokenEntity","OA"));
OAuthAccessToken = OAuthTokenEntity.getProperty("OAuthAccessToken").toString();
OAuthRefreshToken = OAuthTokenEntity.getProperty("OAuthRefreshToken").toString();
}
catch(EntityNotFoundException e)
{
Collection<String> scopes = Arrays.asList(BloggerScopes.BLOGGER);
flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY,
CLIENT_ID, CLIENT_SECRET, scopes)
.setAccessType("offline")
.setApprovalPrompt("auto").build();
String url = flow.newAuthorizationUrl()
.setRedirectUri(OAuthCodeCallbackHandlerServlet.getOAuthCodeCallbackHandlerUrl(request))
.build();
response.sendRedirect("http://OAuthCodeCallbackHandlerServlet");
return;
}
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setClientSecrets(CLIENT_ID, CLIENT_SECRET)
.build();
credential.setAccessToken(OAuthAccessToken);
credential.setRefreshToken(OAuthRefreshToken);
Blogger blog = new Blogger.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName("APP_NAME").setHttpRequestInitializer(credential).build();
}
}
And here is the working version of the Servlet that handles the callback:
public class OAuthCodeCallbackHandlerServlet
{
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String[] code = request.getParameterValues("code");
GoogleTokenResponse tokenResponse = BloggerServlet.flow.newTokenRequest(code[0]).setRedirectUri(getOAuthCodeCallbackHandlerUrl(request)).execute();
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Entity OAuthTokenEntity = new Entity("OAuthTokenEntity","OA");
OAuthTokenEntity.setProperty("OAuthAccessToken", tokenResponse.getAccessToken());
OAuthTokenEntity.setProperty("OAuthRefreshToken",tokenResponse.getRefreshToken());
datastore.put(OAuthTokenEntity);
response.sendRedirect("http://BloggerServlet");
}
public static String getOAuthCodeCallbackHandlerUrl(HttpServletRequest request)
{
StringBuilder oauthURL = new StringBuilder();
oauthURL.append(request.getScheme() + "://");
oauthURL.append(request.getServerName());
oauthURL.append(request.getServerPort() == 80 ? "" : ":" + request.getServerPort());
oauthURL.append(request.getContextPath());
oauthURL.append(URL_MAPPING);
oauthURL.append(request.getPathInfo() == null ? "" : request.getPathInfo());
return oauthURL.toString();
}
}
I have been working on this and my conclusion is:
To make a request for a blog or post, as long as they are public, you don't have to authenticate, i.e. you don't need OAuth for this kind of requests.Still, you have to identify your application and you do that with the APP_KEY. As stated here, not any application can use the Blogger API, it has to be authorized and for this reason is this key needed.
Based on 1., you dont need to create an AppIdentityCredential. I just set the third parameter of Builder to null. I tried using your code but it didn't work.
I still have a question and probably is the same iamkhova has. I think an app can authenticate itself with OAuth using the AppIdentityCredential for GAE apps. But how can you tell google that my application is owner of the blog I am trying to access? I think this is the reason of getting this 401.

Invalid grant in OAuth2 in GAE java appp

Hi i am trying to create a GAE/J app in which i have to retrieve access token from a given code
so here is my code for /oauth2callback servlet
public class OAuth2Callback extends HttpServlet{
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
String url = "https://accounts.google.com/o/oauth2/token";
// FetchOptions opt = FetchOptions.Builder.doNotValidateCertificate();
URL url1=new URL(url);
String param="grant_type=authorization_code&code="+req.getParameter("code")+"&client_id=anonymouns&client_secret=anonymous&redirect_uri=https://www.cloudspokestest.appspot.com/oauth2callback";
HttpURLConnection connection =
(HttpURLConnection)url1.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
connection.getOutputStream().write( param.getBytes() );
InputStream str= connection.getInputStream();
BufferedReader reader=new BufferedReader(new InputStreamReader(str));
String l="";
while((l=reader.readLine())!=null){
resp.getWriter().println(l);
}
}
}
but on the browser screen i am getting error invalid grant with response code 400.can any one please help how to remove this error.
You're getting this error most likely because the parameter values in your url are not url-encoded. The value of the redirect_uri, and possibly the value of code must be url-encoded.
You could use java.net.URLEncoder to encode the values.
Also never use getBytes() on a String, as it uses your platform's default character encoding to convert characters to bytes. Running the same code on another machine, or changing your machines configuration might give different output. Always use getBytes(charsetname) instead.

Categories