Youtube oAuth promts authorization window every time I make request - oauth

Here is my work flow for getting access token and refresh token for youtube api. Im generating authorization url with parameters
access_type=offline, response_type=code, redirect_uri=uri, scope=scopes, state=state, client_id=id
from authorization url I´m receiving authentication code, then I´m generating another url to get access_token and refresh_token using code from authorization url with these parameters
code: code, client_id: CLIENT_ID, client_secret: CLIENT_SECRET, redirect_uri: serviceCallback, state: state.callback, grant_type: "authorization_code"
As far as I know user should complete this process only once and then it should be automatic. My problem is that I´m always have to complete authorization and I´m getting always new access_token and refresh_token without forcing it on request.
here is code part where I´m getting authentication url
getAuthUrl: function(scopes, applicationCallback, serviceCallback, siteId,
selectChannel, websiteUrl) {
var requestedClientId = CLIENT_ID;
var scopess =
"https://www.googleapis.com/auth/yt-analytics.readonly https://www.googleapis.com/auth/youtube.readonly https://www.googleapis.com/auth/userinfo.email " +
scopes.replace(",", " ");
return "https://accounts.google.com/o/oauth2/auth?" +
"access_type=offline" +
"&response_type=code" +
/*"&approval_prompt=auto" +*/
"&redirect_uri=" + serviceCallback +
"&scope=" + scopes +
"&state=" + JSON.stringify({
service: NAME,
callback: applicationCallback,
scopes: scopes,
siteId: siteId,
selectChannel: selectChannel,
websiteUrl: websiteUrl
}) +
"&client_id=" + requestedClientId;
},
From there Im getting back code and using that code, clientID and clientSecret to get access token and refresh token
getAuthTokens: function(code, state, res, serviceCallback) {
// Google oAuth endpoint
var endpoint = "https://www.googleapis.com/oauth2/v4/token";
const scopes = state.scopes.split(" ");
// Setup request data
var data = {
code: code,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
redirect_uri: serviceCallback,
state: state.callback,
grant_type: "authorization_code"
};
request.post(endpoint).send(data).type('form').set('Accept',
'application/json').end(function(err, oAuthResponse) {});
},
I was using wrong endpoint url I changed it to different one to one provided by youtube api documentation and removed state parameter from data variable but still doesnt fix the problem
new endpoint url
var endpoint = "https://accounts.google.com/o/oauth2/token";
I´m really confused right now because I´m not forcing authorization and on google apps section there is my app already authorized and it does not update authorization that means it gives permission only first time and after that when I´m pressing allow it doesn´t do anything. OAuth should check if I have refresh token or not, so my conclusion is that I don´t fully understand how it should work or I´m somehow testing everything on debug or test mode where authorization prompt is automatically forced.
I would be really thankful for any kind of help because I feel like I tried everything.

The issue is that the access token that you are using has expired before the next time you use as you have not updated the access token manually using the refresh token.
You need to use the refresh token to update the access token if [ (time you last updated the access token) + (the expiry time) ] has already surpassed.
The concept of refresh tokens is that if an access token is compromised, as it is short-lived, the attacker has a limited time period in which it can be used. Refresh tokens, if compromised, are useless because the attacker requires the client id and client secret in addition to the refresh token in order to gain an access token.
The YouTube API documentation demonstrates the procedure here
By default, the expiry time is around 3 seconds.
This will surely, work in your case.

Adding the following parameter to your authentication object may help...depending on your requirements:
prompt: 'none'
This would mean no consent is gained or needed, after an initial authorization to use the app.

Go to the my accounts settings of google for this account---> go to connected apps and sites ----> manage apps:
Over there can you see the permissions for youtube like this:

Related

How do I sign access token request withings oauth 1.0

I am currently working on connecting the withings api via web and have been able to automate getting token secret and getting the userId from the callback function inside auth, however when trying to implement step 3 (generating token) I always get signing error. Here is the base logic please help if possible.
nonce = getNonce(32);
date = Math.round((new Date()).getTime() / 1000.0);
var requestSig = oauthSign.hmacsign(
'GET',
'https://oauth.withings.com/account/access_token',
{oauth_consumer_key: <myconsumerkey>,
oauth_nonce: nonce,
oauth_signature_method: 'HMAC-SHA1',
oauth_timestamp: date.toString(),
oauth_token: oauth_token,
oauth_version: '1.0'
}, newSecret);
var hey = encodeURIComponent(requestSig);
var permanentTokensLink = "https://oauth.withings.com/account/access_token?oauth_consumer_key=<myconsumerkey>&oauth_nonce="+nonce+"&oauth_signature="+hey+"&oauth_signature_method=HMAC-SHA1&oauth_timestamp="+date+"&oauth_token="+oauth_token+"&oauth_version=1.0";
return {link:permanentTokensLink, newSecret: newSecret, tokensecret: oauth_token_secret, dataObj: dataObj, token: oauth_token};
newSecrect is a consumersercret&tokensecret, and permanentTokensLink is where I should be able to click to to get the access key and secret. Why is this not working?
I was missing an oauth verifier in the signing params and inside the link I was creating, and the secret should have been broken up into two parts (consumer-secret, token-secret) to be used correctly by the npm package hmacsign.

Microsoft Graph API access token validation failure

I use this URL to get id_token:
https://login.microsoftonline.com/common/oauth2/authorize?
response_type=id_token%20code&
client_id=MY_CLIENT_GUID_ID_IN_HERE&
redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Fopenid%2Freturn&nonce=alfaYYCTxBK8oypM&
state=6DnAi0%2FICAWaH14e
and this return result like this
http://localhost:3000/auth/openid/return?
code=AAA_code_in_here&
id_token=eyJ0eXAi_xxxx_yyyy_in_here&
state=6DnAi0%2FICAWaH14e&
session_state=xxxx_guid_xxxxx
and then i use the id_token to query Graph (use POST man)
i have see this post InvalidAuthenticationToken and CompactToken issues - Microsoft Graph using PHP Curl but make no sense.
OATH 2.0 requires multiple steps. The first request returns an OAUTH Code. The next step is converting that OATUH code into a Bearer Token. This is the step you are missing here.
I would also recommend using the v2 Endpoint which is a lot easier to work with (particularly with Graph). I wrote a v2 Endpoint Primer that walks through the process and may be helpful as well.
You can't use the token directly, there is one more step to exchange the code you get from the response url into token.
Here is my C# code (using Microsoft.IdentityModel.Clients.ActiveDirectory)
public static AuthenticationResult ExchangeCodeForToken(string InTenantName, string InUserObjId, string InRedirectUri, string InApplicationAzureClientID, string InApplicationAzureClientAppKey)
{
Check.Require(!string.IsNullOrEmpty(InTenantName), "InTenantName must be provided");
Check.Require(!string.IsNullOrEmpty(InUserObjId), "InUserObjId must be provided");
if (CanCompleteSignIn) //redirect from sign-in
{
var clientCredential = new ClientCredential(InApplicationAzureClientID, InApplicationAzureClientAppKey);
var authContext = new AuthenticationContext(Globals.GetLoginAuthority(InTenantName), (TokenCache)new ADALTokenCache(InUserObjId)); //Login Authority is https://login.microsoftonline.com/TenantName
return authContext.AcquireTokenByAuthorizationCode(VerificationCode, new Uri(InRedirectUri), clientCredential, Globals.AZURE_GRAPH_API_RESOURCE_ID); //RESOURCE_ID is "https://graph.microsoft.com/"
}
return null;
}
I had this issue today when I was playing with graph API, the problem in my case was how I was generating the token.
I used postman for generating the token wherein the Auth URL section I was adding the resource = client_id whereas it should be the graph URL. After making that change I was able to make the call via postman.
In order for the above to work, please make sure your application in Azure has delegated permissions to access the Graph API.
To receive the access token and use it for profile requests, you don't need anything from server-side, you can implement the oAuth2 just from the client side.
Use the following URL for login:
https://login.microsoftonline.com/common/oauth2/authorize?client_id=YOUR_CLIENT_ID&resource=https://graph.microsoft.com&response_type=token&redirect_uri=YOUR_REDIRECT_URI&scope=User.ReadBasic.All
After successful login, user will redirected to the page with access_token parameter. Then use the following AJAX call to fetch user info:
var token = login_window.location.href.split('access_token=').pop().split('&')[0];
$.ajax({
url: "https://graph.microsoft.com/v1.0/me",
type: "GET",
beforeSend: function(xhr){xhr.setRequestHeader('Authorization', 'Bearer '+token);},
success: function(data) {
alert('Hi '+data.displayName);
console.log(data);
}
});
Note that you may need to enable oauth2AllowImplicitFlow:true setting from your Azure Active Directory application manifest file.
Set "oauth2AllowImplicitFlow": false to "oauth2AllowImplicitFlow": true.
Lastly, ensure that your app has required permissions for Microsoft Graph which are sign in users and View users' basic profile
An updated answer to get access with new applications:
Register your app in the app registration portal.
Authorization request example:
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?client_id=6731de76-14a6-49ae-97bc-6eba6914391e&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F&response_mode=query&scope=offline_access%20user.read%20mail.read&state=12345
Authorization response will look like this:
https://localhost/myapp/?code=M0ab92efe-b6fd-df08-87dc-2c6500a7f84d&state=12345
Get a token
POST /{tenant}/oauth2/v2.0/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&scope=user.read%20mail.read
&code=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq3n8b2JRLk4OxVXr...
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&grant_type=authorization_code
&client_secret=JqQX2PNo9bpM0uEihUPzyrh // NOTE: Only required for web apps
Use the access token to call Microsoft Graph
GET https://graph.microsoft.com/v1.0/me
Authorization: Bearer eyJ0eXAiO ... 0X2tnSQLEANnSPHY0gKcgw
Host: graph.microsoft.com
Source:
https://learn.microsoft.com/en-us/graph/auth-v2-user?context=graph/api/1.0
You can also get an access token without a user, see here:
https://learn.microsoft.com/en-us/graph/auth-v2-service

Issue exchanging LInkedIn javascript token to rest oauth token

I am using the article located at https://developer-programs.linkedin.com/documents/exchange-jsapi-tokens-rest-api-oauth-tokens to exchange my Javascript access token to a REST OAuth token.
After following the directions here, no matter what I seem to do, I only get a 400 Bad Request response back.
The flow I use for Facebook and want to recreate with LinkedIn is; front end authenticates to LinkedIn and passes an access token to my API, the API then gets all necessary user information and passes my own bearer token back to the client, et voila.
Unfortunately LinkedIn doesn't play so nicely with this, and I need to convert my token to an OAuth token from its Javascript token.
I pass the cookie LinkedIn gives me to my API, it looks something like the below (where OAuthBase is http://oauth.googlecode.com/svn/code/csharp/OAuthBase.cs)
access_token: "oxmKI9aU4RCfksdegZ3obZGHK-vo6Q4-4FSQk"
member_id: "AmjWCF7ExN"
signature: "t8KEbLjJ+r6uM42tUwfJm5yWp70="
signature_method: "HMAC-SHA1"
signature_order: ["access_token","member_id"]
signature_version: "1"
I then am attempting to make a call to https://api.linkedin.com/uas/oauth/accessToken to do the actual exchange. My code for this is:
public async Task<IHttpActionResult> ConvertLinkedInToken(LinkedInCovertTokenObject val)
{
string normalizeduri;
string normalizedparams;
OAuthBase o = new OAuthBase();
string signature = o.GenerateSignature(new Uri("https://api.linkedin.com/uas/oauth/accessToken"), Startup.linkedInAuthOptions.ClientId, Startup.linkedInAuthOptions.ClientSecret, val.access_token, null, "POST", o.GenerateTimeStamp(), o.GenerateNonce(), out normalizeduri, out normalizedparams);
var client = new HttpClient();
var uri = new Uri("https://api.linkedin.com/uas/oauth/accessToken?" +
"oauth_consumer_key=" + Startup.linkedInAuthOptions.ClientId +
"&xoauth_oauth2_access_token=" + val.access_token +
"&signature_method=HMAC-SHA1" +
"&signature=" + signature
);
var response = await client.GetAsync(uri);
return Ok();
}
No matter how I play around all I get back from LinkedIn is a 400 Bad Request without any other useful information.
1) How can I convert LinkedIn JS token to Rest OAuth token in my c# api
This is how I achieved that:
On the frontend:
IN.User.authorize(function(){
// here you can find oauth token
var oauth_token = IN.ENV.auth.oauth_token;
// send this token to your API endpoint
});
On your API (curl example), of course replace OAUTH_TOKEN with token received on the frontend.
curl -X GET \
'https://api.linkedin.com/v1/people/~:
(id,firstName,lastName,siteStandardProfileRequest,picture-url,email-
address)?format=json' \
-H 'oauth_token: OAUTH_TOKEN'
You are looking at old documentation from LinkedIn. Starting from 12th May, LinkedIn has started rolling out new changes in their API which includes authentication. In my knowledge, LinkedIn is not using OAuth anymore, and you need OAuth2.0 henceforth for authentication. You should check this link for more information:
https://developer.linkedin.com/docs/signin-with-linkedin

How can I refresh a google plus bearer token (javascript)?

I'm using the google HTML sign-in button in my single page (javascript) application to obtain an authorization object from users with Google logins. This is detailed here: https://developers.google.com/+/web/signin/add-button.
I successfully receive back a token such as shown below. Since this token expires in 1 hour, I need to refresh the token every 30 minutes or so, until the user choses to log out. I am attempting this by calling:
gapi.auth.authorize({client_id: "90... ...92.apps.googleusercontent.com", scope: "profile email", immediate: true}, function() { console.log( arguments ); } );
but with no luck. I receive the same token back until it expires, after which I get back the empty (not signed in) token. How can I preserve / refresh the bearer token without the user having to continually log in again?
{
_aa: "1"
access_token: "ya29.1.AA... ...BByHpg"
authuser: "0"
client_id: "90... ...92.apps.googleusercontent.com"
code: "4/Nyj-4sVVcekiDnIgMFh14U7-QdRm.svPMQSODiXMbYKs_1NgQtmX9F90miwI"
cookie_policy: "single_host_origin",
expires_at: "1398341363",
expires_in: "3600",
g_user_cookie_policy: undefined,
id_token: "eyJhbGciOiJ... ...0Es1LI"
issued_at: "1398337763",
num_sessions: "2",
prompt: "none",
response_type: "code token id_token gsession",
scope: "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
session_state: "b92d67080... ...73ae",
state: "",
status: {
google_logged_in: true,
method: "AUTO",
signed_in: true
},
token_type: "Bearer"
}
Using the client side flow (ie Java Script) you can only receive short-lived (~1 hour) access_token. If you want to be able to refresh it, you need a refresh_token which can only be obtained using the server side flow.
You can find more information here.
Basically,it works like this :
The user connects to your Website and clicks on the "Sign-in button"
You receive an access_token and a code in JavaScript
You send this code to a PHP Script on your web server
The script makes a request to Google Servers and exchanges your code for an
access_token(which should be identical to the one you just received in JavaScript) and a refresh_token
You need to store this refresh_token somewhere (in a data base for
example) because it will only be issued once (when the users grants
permission)
When one of your access_token is about to expire, you can use your
refresh_token to get another valid access_token
As well as setting a timer, you should check that your token is still valid before making the API call. Now that the client library returns promises, and promises are chainable, you can do it really elegantly.
See my gist here.

can't get access token using refresh token

I wrote desktop application on java, which have access to the Google drive. (it just uploads and downloads files).
At the moment access type is online. when I need to access files/folders to the drive, I
redirect he browser to a Google URL and get access code:
String code = "code that was returned from brouser"
GoogleTokenResponse response = flow.newTokenRequest(code).setRedirectUri(REDIRECT_URI).execute();
GoogleCredential credential = new GoogleCredential().setFromTokenResponse(response);
everything works well! but I need to have that redirection only first time.
When I google, in the Google Drive API documentation I found that I can get refresh token via browser redirection and save it on DB for instance. (In the other word, I can use offline access).
And every time when I need to read data from google drive, I get access token using refresh token without redirection. is not it?
so I get refresh token like that:
https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=695230079990.apps.googleusercontent.com&scope=https://www.googleapis.com/auth/drive&response_type=code&redirect_uri=https://localhost
question 1
I get code, from the browser redirecting. it's refresh token, is not it?
now, I need to get access token using that refresh token.
$.ajax({
type: "POST",
url: 'https://accounts.google.com/o/oauth2/token',
data: {
client_id: "695230079990.apps.googleusercontent.com",
client_secret: 'OWasYmp7YQ...4GJaPjP902R',
refresh_toke: '4/hBr......................xwJCgQI',
grant_type: 'refresh_token'
},
success: function(response) {
alert(response);
}
});
but I have error 400;
question 2) when I try to change redirect url I have that error: *
Invalid parameter value for redirect_uri: Non-public domains not allowed: https://sampl.ecom
so, must I create web applications Client ID , instead of installed application from google APIs console? Can't I change Redirect URI in installed application? I'm confused, I don't know, which should I use.
1) when you try to have offline access, you get authorization code which may be redeemed for an access token and a refresh token.
For isntance:
https://accounts.google.com/o/oauth2/auth?access_type=offline
&approval_prompt=auto
&client_id=[your id]
&redirect_uri=[url]
&response_type=code
&scope=[access scopes]
&state=/profile
after you get authorization code, you cat get refresh token.
static Credential exchangeCode(String authorizationCode)
throws CodeExchangeException {
try {
GoogleAuthorizationCodeFlow flow = getFlow();
GoogleTokenResponse response =
flow.newTokenRequest(authorizationCode).setRedirectUri(REDIRECT_URI).execute();
return flow.createAndStoreCredential(response, null);
} catch (IOException e) {
System.err.println("An error occurred: " + e);
throw new CodeExchangeException(null);
}
}
See the section on Implementing Server-side Authorization tokens for more information.
and after you get refresh token , you must save it. see that sample for mor information.
2) If you don't have installed application, you should create web applications to change redirecting URL.

Resources