Using google spreadsheet api with OAuth2 - oauth-2.0

As Google has deprecated use of OAuth1, I am trying to migrate my application to OAuth2. I am using Service Account and trying to read a Google spreadsheet. I am able to get the access token but still not able to get the spreadsheets associated with my account.Below is the code I am using,please let me know where am I making a mistake. :
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
String SPREADSHEET_URL = "https://spreadsheets.google.com/feeds/spreadsheets/private/full";
URL SPREADSHEET_FEED_URL = new URL(SPREADSHEET_URL);
String[] SCOPESArray = { "https://spreadsheets.google.com/feeds" };
final List SCOPES = Arrays.asList(SCOPESArray);
GoogleCredential credential = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId("28031770151-826a7iuekrsmr0gf4kc####iiop#developer.gserviceaccount.com")
.setServiceAccountScopes(SCOPES).setServiceAccountPrivateKeyFromP12File(new File("key.p12"))
.build();
System.out.println(credential.getAccessToken());
credential.refreshToken();
credential.getRefreshToken();
SpreadsheetService service = new SpreadsheetService("inlaid-chassis-9640");
service.setOAuth2Credentials(credential);
SpreadsheetFeed feed = service.getFeed(SPREADSHEET_FEED_URL, SpreadsheetFeed.class);
List<SpreadsheetEntry> spreadsheets = feed.getEntries();
// spreadsheets comes out be a blank array

Solved! For this we need to share our spreadsheet with the service account id/email Id(refer the code above) generated while creating the project on https://console.developers.google.com.

Related

Unable to find DiscoveryClient for IdentityServer4

Trying to access discovery client for acceising other endpoints anf following with,
http://docs.identityserver.io/en/aspnetcore1/endpoints/discovery.html
Installed IdentityModel nuget package in .Net 7.5 MVC application. But unable to find the DiscoveryClient.
var discoveryClient = new DiscoveryClient("https://demo.identityserver.io");
var doc = await discoveryClient.GetAsync();
Is there something change in Identitymodel for IdentityServer4
Also, unable to find parameter for "Tokenclient".
Able to figure out, change in IdentityModel, its all extension of HttpClient.
https://identitymodel.readthedocs.io/en/latest/client/discovery.html
var client = new HttpClient();
var disco = await client.GetDiscoveryDocumentAsync("https://demo.identityserver.io");
Yes, you are correct. There are lot of changes in the IdentityModel NuGet package.
Below code will help you:
HttpClient httpClient = new HttpClient();
//Below code will give you discovery document response previously we were creating using DiscoveryClient()
// They have created `.GetDiscoveryDocumentAsync()` extension method to get discovery document.
DiscoveryDocumentResponse discoveryDocument = await httpClient.GetDiscoveryDocumentAsync();
// To create a token you can use one of the following methods, which totally depends upon which grant type you are using for token generation.
Task<TokenResponse> RequestAuthorizationCodeTokenAsync(AuthorizationCodeTokenRequest)
Task<TokenResponse> RequestClientCredentialsTokenAsync(ClientCredentialsTokenRequest)
Task<TokenResponse> RequestDeviceTokenAsync(DeviceTokenRequest)
Task<TokenResponse> RequestPasswordTokenAsync(PasswordTokenRequest)
Task<TokenResponse> RequestRefreshTokenAsync(RefreshTokenRequest)
Task<TokenResponse> RequestTokenAsync(TokenRequest)
For example if you want to create a token for password grant type then use below code:
PasswordTokenRequest passwordTokenRequest = new PasswordTokenRequest()
{
Address = discoveryDocument.TokenEndpoint,
ClientId = ClientName,
ClientSecret = ClientSecret,
GrantType = GrantTypes.ResourceOwnerPassword,
Scope = scope,
UserName = userName,
Password = password
};
httpClient.RequestPasswordTokenAsync(passwordTokenRequest);
I hope this will help you!
If you used some sample code and the other answers aren't working, because HttpClient doesn't have GetDiscoveryDocumentAsync
var client = new HttpClient();
var disco = await client.GetDiscoveryDocumentAsync("https://localhost:5001");
Update your IdentityModel package, in Visual Studio:
Right click Dependencies -> Manage Nuget Packages -> Updates (select "All" in top right corner)

OAuth with multiple youtube accounts

I am writing a Windows desktop application that uploads video to youtube. I am using the code below.
UserCredential credential;
/*
using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
{
// dependent on the client_secrets.json file
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
// This OAuth 2.0 access scope allows an application to upload files to the
// authenticated user's YouTube channel, but doesn't allow other types of access.
new[] { YouTubeService.Scope.YoutubeUpload },
"user",
CancellationToken.None
);
}*/
ClientSecrets clientSecret = new ClientSecrets();
clientSecret.ClientId = "xxx.apps.googleusercontent.com";
clientSecret.ClientSecret = "yyyyyy";
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
clientSecret,
new[] { YouTubeService.Scope.YoutubeUpload },
"user",
CancellationToken.None);
What I have not been able to determine is how to switch between different youtube accounts. I have more than one youtube account and would like to use them for different scenarios within the desktop application.
When I originally used the commented out snippet of code, it used the json file for the user credentials - but that is static information. I then changed the code to what you see above - but intend to change the code to use different values for ClientSecret to select the corresponding youtube account.
The first time I ran the application, it prompts me to select which google/youtube account to use - and works correctly - but I do not know how to switch to different accounts in code. I have read through the google api on this, but cannot determine how to do this. I have tried not providing a ClientSecret, but then get an exception that no ClientSecret was provided, which makes sense.

MVC5 app using Azure Active Directory + REST API -- to auth for PowerBI / O365

I'm trying to adapt the WebAPI example shown here, to use in MVC5:
https://msdn.microsoft.com/en-US/library/dn931282.aspx#Configure
I have a regular AccountController based login system, but I also need the user to login via OAuth into PowerBI, so I can pull datasets via the PowerBI REST API. However, I'm gettting the ClaimsPrincipal.Current.FindFirst(..) to be null.
private static async Task<string> getAccessToken()
{
// Create auth context (note: token is not cached)
AuthenticationContext authContext = new AuthenticationContext(Settings.AzureADAuthority);
// Create client credential
var clientCredential = new ClientCredential(Settings.ClientId, Settings.Key);
// Get user object id
var userObjectId = ClaimsPrincipal.Current.FindFirst(Settings.ClaimTypeObjectIdentifier).Value;
// Get access token for Power BI
// Call Power BI APIs from Web API on behalf of a user
return authContext.AcquireToken(Settings.PowerBIResourceId, clientCredential, new UserAssertion(userObjectId, UserIdentifierType.UniqueId.ToString())).AccessToken;
}
It all works fine in the sample app (a WebAPI project). I've also configured the OWIN app.UseOpenIdConnectAuthentication stuff in Startup.Auth.cs.
It seems the issue is the only type of Claim I have in 'ClaimsPrincipal.Current' is a 'CookieAuthentication' - it is missing the http://schemas.microsoft.com/identity/claims/objectidentifier Claim.
Also...the Microsoft OAuth window never opens in the browser...however, the error is within the ActiveDirectory related code...that code shouldn't need an OAuth token in the first place, right?
The recommended way to do this is to use the code that the Open ID Connect middleware will automatically retrieve for you. There is relevant sample here:
https://github.com/AzureADSamples/WebApp-WebAPI-OpenIDConnect-DotNet
This sample uses OAuth to get a token for the AAD Graph API. I don't know PowerBI but I believe that this is exactly analogous to getting a token for PowerBI.
Pay attention in particular to this file:
https://github.com/AzureADSamples/WebApp-WebAPI-OpenIDConnect-DotNet/blob/master/TodoListWebApp/App_Start/Startup.Auth.cs
AuthorizationCodeReceived = (context) =>
{
var code = context.Code;
ClientCredential credential = new ClientCredential(clientId, appKey);
string userObjectID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
AuthenticationContext authContext = new AuthenticationContext(Authority, new NaiveSessionCache(userObjectID));
AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, graphResourceId);
return Task.FromResult(0);
},
The code above is called on every successful authentication, and ADAL is used to retrieve a token to the Graph API. At this point the only reason to get a token for the Graph API is to exchange the short lived auth code for a longer lived refresh token and get that stored in the cache. That is why the 'result' is never used.
Later, in the following file, the cache is employed to retrieve the token and use it to access the graph:
https://github.com/AzureADSamples/WebApp-WebAPI-OpenIDConnect-DotNet/blob/master/TodoListWebApp/Controllers/UserProfileController.cs
string tenantId = ClaimsPrincipal.Current.FindFirst(TenantIdClaimType).Value;
string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
AuthenticationContext authContext = new AuthenticationContext(Startup.Authority, new NaiveSessionCache(userObjectID));
ClientCredential credential = new ClientCredential(clientId, appKey);
result = authContext.AcquireTokenSilent(graphResourceId, credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
This time the token is actually used.
Substitute PowerBI for Graph API in the sample and I think you should be good to go.
Note that one other thing to pay attention to is the cache implementation. This file contains an appropriately name NaiveSessionCache.
https://github.com/AzureADSamples/WebApp-WebAPI-OpenIDConnect-DotNet/blob/master/TodoListWebApp/Utils/NaiveSessionCache.cs
If you have multiple front ends you will need to implement your own, less naive, session cache so that all the front ends can share the same cache.
A potential workaround, at least for me, is to use the "native app" setup on Azure AD and follow this workflow, instead of the web app + oauth workflow:
https://msdn.microsoft.com/en-US/library/dn877545.aspx

DFA Reporting: Unable to fetch profiles using Service Account

I am developing a piece of code which can create and download reports using Google DFA Reporting API's.
I am able to do the same using Client Id and Client Secret, which is generated using Install-App (native Application) account, but with this type of account, it always open a browser for first time and then only it authenticates the future request.
On further reading, I came across the service account. I then created a new Service Account and downloaded p12 key. I am now able to build credential object with the help of p12 and Email account (*******ccms#developer.gserviceaccount.com). I can confirm this as I am seeing access token in a credential object after calling credentials.refreshToken().
I then create an object of DFA Reporting using the above credential and trying to fetch profiles list, but I am getting the below error:
java.lang.IllegalArgumentException: No profiles found
at com.google.api.client.repackaged.com.google.common.base.Preconditions.checkArgument(Preconditions.java:92)
at com.google.api.client.util.Preconditions.checkArgument(Preconditions.java:49)
at com.google.api.services.samples.dfareporting.cmdline.GetAllUserProfiles.list(GetAllUserProfiles.java:52)
at com.google.api.services.samples.dfareporting.cmdline.DfaReportingSample.main(DfaReportingSample.java:171)
Please see my code below and let me know where I am going wrong:
private static Credential authorize() throws Exception {
// load client secrets
List<String> SCOPES = ImmutableList
.of("https://www.googleapis.com/auth/dfareporting");
String SERVICE_ACCOUNT_EMAIL = "*************************#developer.gserviceaccount.com";
String Path = DfaReportingSample.class.getResource(
"/TestDFA-5d985ff38b34.p12").getPath();
java.io.File file = new java.io.File(Path);
HttpTransport httpTransport = new NetHttpTransport();
JacksonFactory jsonFactory = new JacksonFactory();
Credential credentials = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(SCOPES)
.setServiceAccountPrivateKeyFromP12File(file).build();
credentials.refreshToken();
return credentials;
}
private static Dfareporting initializeDfareporting() throws Exception {
Credential credential = authorize();
// Create DFA Reporting client.
return new Dfareporting(httpTransport, JSON_FACTORY, credential);
}
public static void main(String[] args) {
try {
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
Dfareporting reporting = initializeDfareporting();
UserProfiles up = reporting.userProfiles();
List l = up.list();
UserProfileList profiles = l.execute();
// {"etag":"\"bM2H6qONz9kIDiByk_eTdC6Ehcc/vyGp6PvFo4RvsFtPoIWeCReyIC8\"","items":[],"kind":"dfareporting#userProfileList"}
Preconditions.checkArgument(
profiles.getItems() != null && !profiles.getItems().isEmpty(), "No profiles found");
for (UserProfile userProfile : profiles.getItems()) {
System.out.printf("User profile with ID \"%s\" and name \"%s\" was found.%n",
userProfile.getProfileId(), userProfile.getUserName());
}
....................................
PS: I am able to fetch all the profiles, if I use access token which is generated using client id and client secret provided by native application (installed apps) account.
Thanks,
Hussain Bohra
After trying a lot with service account (& p12 key), we couldn't make it work with the Google DFA Reporting. Hence we are now using the following class for authentication:
com.google.api.ads.common.lib.auth.OfflineCredentials
input = new FileInputStream(Utils.getProperty(Constants.HOME_PATH)
+ Utils.getProperty(Constants.CLIENT_SECRETS_DIRECTORY)
+ Constants.PATH_SEPARATOR + userPropertyFile);
userProperty.load(input);
credential = new OfflineCredentials.Builder()
.forApi(OfflineCredentials.Api.DFA)
.withHttpTransport(
GoogleNetHttpTransport.newTrustedTransport())
.withClientSecrets(userProperty.getProperty("client_id"),
userProperty.getProperty("client_secret"))
.withRefreshToken(userProperty.getProperty("refresh_token"))
.build().generateCredential();
The refresh token used in the above code is generated manually (one time process) for every account. Using this object of credential, we are now able to perform all the following activities in a DFA reporting:
- List Profiles
- Validate and Create Report
- Download Report Data.
Code to get refresh token (involves a manual step of clicking Accept in a browser)
java.io.File DATA_STORE_DIR = new java.io.File(
"d:/dfa-reporting/.store/dfareporting_sample");
FileDataStoreFactory dataStoreFactory;
dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(
JSON_FACTORY,
new InputStreamReader(DfaReportingSample.class
.getResourceAsStream("/client_secret_galtieri.json")));
// set up authorization code flow
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(dataStoreFactory).build();
// authorize
String refreshToken = new AuthorizationCodeInstalledApp(flow,
new PromptReceiver()).authorize("hbohra").getRefreshToken();
Thanks,
Hussain Bohra

Oauth2.0 authentication Google Adsense

I am trying to authenticate using Oauth2. My earlier implementations was using OAuth2Draft10 but since its deprecated now, so I wanted to move to OAuth2.0 http://www.proksi.us/browse.php?u=Oi8vY29kZS5nb29nbGUuY29tL3AvZ29vZ2xlLWFwaS1qYXZhLWNsaWVudC93aWtpL09BdXRoMg%3D%3D&b=143
Mine is an installed application and I am following http://www.proksi.us/browse.php?u=Oi8vY29kZS5nb29nbGUuY29tL3AvZ29vZ2xlLWFwaS1qYXZhLWNsaWVudC93aWtpL09BdXRoMg%3D%3D&b=143#Installed_Applications
but facing problem while calling the authorize() method here, could not get through VerificationCodeReceiver.
Any Help or any guide from where I can get through where I am wrong or missing..?
Resolved ..:)
No need to VerificationCodeReceiver.
public static Credential authorize() throws Exception {
// load client secrets
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(
JSON_FACTORY, AdSenseSample.class.getResourceAsStream("/client_secrets.json"));
// set up file credential store
File jsonFile = new File("/adsense.json");
FileCredentialStore credentialStore = new FileCredentialStore(jsonFile, JSON_FACTORY);
// set up authorization code flow
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets,
Collections.singleton(AdSenseScopes.ADSENSE_READONLY)).setCredentialStore(
credentialStore).build();
// authorize
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
}
Thanks..:)

Resources