I ask my client to hit at this URL with his authorized gmail account with which he has created the google api project.
https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri=http://www.XXXXXXXX.com/oauth2callback&client_id=XXXXXX.apps.googleusercontent.com&state=profile&approval_prompt=force
and then ask him to provide me the code parameter from the redirected URL
http://www.XXXXXXXX.com/oauth2callback?code=4/jUxc2MdX0xmF-b4_I6v2SLMQMuxO.cvQLVEpcJMUXOl05ti8ZT3ZvsT9ddwI
Then i myself post this form with following info.
<form action="https://accounts.google.com/o/oauth2/token" method="post" >
<input type="hidden" name="grant_type" value="authorization_code" >
<input type="text" name="code" value="**is the one i recieved from previous step**">
<input type="hidden" name="client_id" value="XXXXXXX.apps.googleusercontent.com" >
<input type="hidden" name="client_secret" value="XXXXXXXXXXXX" >
<input type="hidden" name="redirect_uri" value="http://www.XXXXXX.com/oauth2callback" >
<input type="submit" value="Submit">
</form>
and then i get the following error
{
"error" : "invalid_grant"
}
When i generate the code url param myself and perform the next step. i am successfully presented with following response
{
"access_token" : "XXXXXXStBkRnGyZ2mUYOLgls7QVBxOg82XhBCFo8UIT5gM",
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : "XXXXXX3SEBX7F2cfrHcqJEa3KoAHYeXES6nmho"
}
But if the client generate the url param "code" then i see the invalid grant error.
My Client is in UK and i am in another country. Can anybody please confirm if it's the error because client is generating the code param in another country and i am using that code in another country ?
Thanks in advance.
I got annoyed by invalid_grant error instead of the fact that same code is getting me correct access token some times.
Shaikh's answer has guided me to correct direction.
First of all we try to get access code from:
https://accounts.google.com/o/oauth2/auth
User is directed to "Allow Permission" screen and then our app receive access code.
Using that access code we try to get access token from:
https://accounts.google.com/o/oauth2/token
In the first attempt it will return us access_token with grant_type=authorization_code, but once access_token has been provided to us, it no longer expect to receive grant_type=authorization again, instead it likes to receive grant_type=refresh_token
For fellow android developers code is as follows:
String accessToken = null, refreshToken = null;
HttpPost httppost = new HttpPost(https://accounts.google.com/o/oauth2/token);
HttpParams myParams = new BasicHttpParams();
httppost.setHeader("Content-type", "application/x-www-form-urlencoded");
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(4);
nameValuePairs.add(new BasicNameValuePair("client_id", BLOGGER_CLIENT_ID));
SharedPreferences prefs = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
String bloggerAccessToken = prefs.getString(PREFERENCES_KEY_BLOGGER_ACCESS_TOKEN, null);
if(bloggerAccessToken != null && bloggerAccessToken.length() > 0){
nameValuePairs.add(new BasicNameValuePair("refresh_token", prefs.getString(PREFERENCES_KEY_BLOGGER_REFRESH_TOKEN, null)));
nameValuePairs.add(new BasicNameValuePair("grant_type", "refresh_token"));
} else{
nameValuePairs.add(new BasicNameValuePair("code", prefs.getString(PREFERENCES_KEY_BLOGGER_ACCESS_CODE, null)));
nameValuePairs.add(new BasicNameValuePair("grant_type", "authorization_code"));
nameValuePairs.add(new BasicNameValuePair("redirect_uri", "http://localhost"));
}
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpClient httpClient = new DefaultHttpClient(myParams);
response = httpClient.execute(httppost);
String returnedJsonStr = EntityUtils.toString(response.getEntity());
JSONObject jsonObject = new JSONObject(returnedJsonStr);
accessToken = jsonObject.getString("access_token");
if(jsonObject.has("refresh_token"))
refreshToken = jsonObject.getString("refresh_token");
You may ask the client to generate the code PLUS the subsequent refresh token himself. Give him the access to the form above where the refresh_token is generated.
Then you can use refresh_token to generate access_tokens.
Hope it fixes your problem.
Related
how to Use the client ID and client secret to obtain an access token using the OAuth 2.0 protocol
please give me an example
you can also get token via ajax run this code in php file
<p id="demo"></p>
<button type="button" onclick="loadDoc()">Request data</button>
Request data
<script>
function loadDoc() {
const xhttp = new XMLHttpRequest();
xhttp.onload = function() {
document.getElementById("demo").innerHTML = this.responseText;
}
xhttp.open("POST", "https://www.googleapis.com/oauth2/v4/token");
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send("code=<?=$_REQUEST['code']?>&client_id=your_client_id&client_secret=your_client_secret&redirect_uri=your_redriction_url&grant_type=authorization_code");
}
</script>
I have read many posts, all the Google documentation I can find and tried many iterations of the following and still can't get an access and refresh token. I do get an authorization code but can't seem to get that to trade for the access and refresh tokens.
if(authCode == null || authCode.equals("")) {
String url = "https://accounts.google.com/o/oauth2/v2/auth?"
+ "scope=https://mail.google.com/&"
+ "response_type=code&"
+ "redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&"
+ "client_id=" + clientId +
"&access_type=offline";
URI uri = new URI(url);
logger.debug("URI for auth is: " + uri);
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
Desktop.getDesktop().browse(uri);
}
}
else {
logger.debug("Refreshing");
initRefreshToken();
}
With that, I get an access code I can cut and paste (just testing and trying to get this to work first) in my properties to get the refresh and access token.
In the initRefreshToken() method, the source is like this:
if(refreshToken.equals("")) {
logger.debug("Getting refresh token");
HttpPost post = new HttpPost("https://oauth2.googleapis.com/token");
// add request parameter, form parameters
List<NameValuePair> urlParameters = new ArrayList<>();
urlParameters.add(new BasicNameValuePair("code", authCode));
urlParameters.add(new BasicNameValuePair("client_id", clientId));
urlParameters.add(new BasicNameValuePair("client_secret", clientSecret));
urlParameters.add(new BasicNameValuePair("redirect_uri", "http://localhost:8000/"));
urlParameters.add(new BasicNameValuePair("grant_type", "authorization_code"));
try {
post.setEntity(new UrlEncodedFormEntity(urlParameters));
System.out.println("***** URL: " + urlParameters);
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(post);
System.out.println(EntityUtils.toString(response.getEntity()));
}
If this is a second or subsequent time using the code, what will be printed is:
Refersh token:
***** URL: [code=4/1AY0e-g..., client_id=370...i1h2u1s.apps.googleusercontent.com, client_secret=bAOH..., redirect_uri=https://localhost:8000/, grant_type=authorization_code]
{
"error": "invalid_grant",
"error_description": "Bad Request"
}
If the code is run and it's the first time using an authentication code, it will print:
{
"error": "redirect_uri_mismatch",
"error_description": "Bad Request"
}
I read in the Google console that exceptions are made for localhost domains so there's no need to register them. However, if there were a need to register them, it won't let you register them anyway as a domain must be a top level domain you own in order to register it. Therefore, how do I register localhost and/or exchange an authorization code for an access and refresh token in Java?
Thank you for your help.
DaImTo provided a great video about this and in that video and the blog post associated with it, the redirect_uri is listed correctly as: "urn:ietf:wg:oauth:2.0:oob". I didn't find this in the documentation but when I added it to my source code, I got access and refresh tokens as a response. Thank you very much for that help, DaImTo.
This is my first exercise in angular8. I am on the attempt to make a form that consumes an API written in springboot. The api written in spring-boot is never executed when trying to consume it from angular8 and here is the endpoint
http://localhost:8080/api/startreg
#PostMapping("/startreg")
public ResponseData<Activity> addReg(
#RequestParam(value="firstDate") String firstDate,#RequestParam(value="secondDate") String secondDate
,#RequestParam(value="username") String username) {
try {
Here is the service.ts script
private baseUrl = 'http://localhost:8080/api/startreg';
createReg(activity: Object): Observable<Object> {
return this.http.post('${this.baseUrl}', activity);
}
the html file of the angular8 is shown
<form (ngSubmit)="onSubmit()">
<div class="col-md-3 col-sm-5 col-xs-12 gutter">
<div class="sales">
<h2>From:</h2>
<div class="btn-group">
<select [(ngModel)]="activity.firstDate" class="form-control" name="firstDate">
when I attempt to submit the form, from the browser console below error
HttpErrorResponse {headers: HttpHeaders, status: 404, statusText: "Not Found", url: "http://localhost:4202/$%7Bthis.baseUrl%7D", ok: false, …}
Please where I am getting it wrong
Because this.http.post('${this.baseUrl}', activity); won't invoke service with the value of this.baseUrl, you can find out why according to the error message.
The URL you passed to post is still a string not a variable.
Please modify service.ts as follows:
...
return this.http.post(this.baseUrl, activity);
}
UPDATE
Another problem is your service consumes request parameters, so you have to pass these URL arguments for HTTP request in service.ts.
The valid URL should look like this:
http://localhost:8080/api/startreg?firstDate=XXX&secondDate=XXX&username=XXX
But I am not familar with TypeScript, so I don't know how to do this. Maybe you can refer to Angular2 - Http POST request parameters.
BTW, I strongly recommend that you should use #RequestBody rather than #RequestParam for your POST service.
I'm trying to use the authorization flow outlined at https://developers.google.com/identity/sign-in/web/server-side-flow.
I've created the credentials as indicated... with no Authorized redirect URIs specified as the doc indicates: "The Authorized redirect URI field does not require a value. Redirect URIs are not used with JavaScript APIs."
The code initiating the authorization is:
Client button and callback:
<script>
$('#signinButton').click(function() {
var auth2 = gapi.auth2.getAuthInstance();
auth2.grantOfflineAccess().then(signInCallback);
});
function signInCallback(authResult) {
console.log('sending to server');
if (authResult['code']) {
// Send the code to the server
$.ajax({
type: 'POST',
url: 'CheckAuth',
headers: {
'X-Requested-With': 'XMLHttpRequest'
},
contentType: 'application/octet-stream; charset=utf-8',
success: function(result) {
// Handle or verify the server response.
},
processData: false,
data: authResult['code']
});
} else {
// There was an error.
}
}
</script>
Server side (CheckAuth method to create credentials from auth code, which it receives correctly via the javascript callback):
private Credential authorize() throws Exception {
// load client secrets
InputStream is = new FileInputStream(clientSecretsPath_);
InputStreamReader isr = new InputStreamReader(is);
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, isr);
String redirect_URI = "";
GoogleTokenResponse tokenResponse =
new GoogleAuthorizationCodeTokenRequest(
httpTransport, JSON_FACTORY,
"https://www.googleapis.com/oauth2/v4/token",
clientSecrets.getDetails().getClientId(),
clientSecrets.getDetails().getClientSecret(),
token_,
redirect_URI)
.execute();
String accessToken = tokenResponse.getAccessToken();
// Use access token to call API
GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken);
return credential;
}
The flow works correctly, up until the point my server attempts to exchange the authorization code for the token response (GoogleAuthorizationCodeTokenRequest.execute() )... the auth server returns:
400 Bad Request
{
"error" : "invalid_request",
"error_description" : "Missing parameter: redirect_uri"
}
Given the error, I looked in debug at the auth instance in javascript and noted what it indicated was the redirect_uri. I then updated my google credentials and specified that URI in the Authorized redirect URIs (it's the URL that accessed the javascript, as the auth server correctly returns to the specified javascript callback). With the updated credentials and the URI specified in the instantiation of GoogleAuthorizationCodeTokenRequest (String redirect_URI = "http://example.com:8080/JavascriptLocation";), the error then becomes:
400 Bad Request
{
"error" : "redirect_uri_mismatch",
"error_description" : "Bad Request"
}
I've tracked all the way through to the actual HttpRequest to the auth server (www.googleapis.com/oauth2/v4/token) and cannot tell what redirect_uri it is looking for.
Does anyone know what the value of redirect_uri should be in this case (when using grantOfflineAccess())? I'm happy to post more of the code, if that is at all helpful... just didn't want to flood the page. Thanks.
Found a reference to "postmessage" right after posting the question... using it as the redirect_URI on the server side seems to generate a successful response from the auth server. So... setting redirect_URI="postmessage" in the code below appears to work in this situation.
GoogleTokenResponse tokenResponse =
new GoogleAuthorizationCodeTokenRequest(
httpTransport, JSON_FACTORY,
"https://www.googleapis.com/oauth2/v4/token",
clientSecrets.getDetails().getClientId(),
clientSecrets.getDetails().getClientSecret(),
token_,
redirect_URI)
.execute();
i'm having a page with google+ sign in button in this page www.mawk3y.net/glogin and here's the code
head code :
<script type="text/javascript">
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/client:plusone.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
function signinCallback(authResult) {
if (authResult['access_token']) {
alert("done");
// Successfully authorized
// Hide the sign-in button now that the user is authorized, for example:
document.getElementById('signinButton').setAttribute('style', 'display: none');
} else if (authResult['error']) {
// There was an error.
// Possible error codes:
// "access_denied" - User denied access to your app
// "immediate_failed" - Could not automatically log in the user
// console.log('There was an error: ' + authResult['error']);
}
}
</script>
body code:
<span id="signinButton">
<span
class="g-signin"
data-callback="signinCallback"
data-clientid="451331211615.apps.googleusercontent.com"
data-cookiepolicy="single_host_origin"
data-requestvisibleactions="http://schemas.google.com/AddActivity"
data-scope="https://www.googleapis.com/auth/plus.login">
</span>
</span>
still the most important part which is how to retrieve the user information from google like name,email,gender,country any help please ?
Once you have authenticated a user, and they have authorized you to get information about them, you can make calls to get that information using the plus.people.get method, or other related methods. See https://developers.google.com/+/web/people/ for the overview and links to more detailed information.
Specifically, you can see a code fragment at https://developers.google.com/+/web/people/#retrieve_profile_information that will retrieve all of a person's public data except for their email address. Typically, you would call this fragment as part of the loginFinishedCallback (shown further down on that page) once you have verified the authentication was good.