I am trying to get access to my google calendar via google credentials.
GoogleCredential credentials = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId("xxx#developer.gserviceaccount.com")
.setServiceAccountScopes(Arrays.asList("https://www.googleapis.com/auth/calendar"))
.setServiceAccountPrivateKeyFromP12File(new File("Disk:\\xxx-privatekey.p12"))
.setServiceAccountUser("xxx#gmail.com").build();
Calendar service = new Calendar.Builder(httpTransport, jsonFactory, credentials)
.setApplicationName("CalendarTest").build();
but when I want to do smth with a calendar like
com.google.api.services.calendar.model.Calendar calendar = service.calendars().get("primary").execute();
System.out.println(calendar.getSummary());
I get an error
com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
"error" : "access_denied",
"error_description" : "Requested scopes not allowed: https://www.googleapis.com/auth/calendar"
}
Related
I currently have a ASP.Net Core Web Api with Blazor WASM which can login successfully to Google OAuth using the component RemoteAuthenticatorView. My intention is now to pass the token I have to the web api, which hopefully can be used to authenticate with the web api. The issue is that TokenProvider.RequestAccessToken() produces the following error.
blazor.webassembly.js:1 Microsoft.JSInterop.JSException: An exception occurred executing JS interop: The JSON value could not be converted to System.DateTimeOffset. Path: $.token.expires | LineNumber: 0 | BytePositionInLine: 88.. See InnerException for more details.
System.Text.Json.JsonException: The JSON value could not be converted to System.DateTimeOffset. Path: $.token.expires | LineNumber: 0 | BytePositionInLine: 88.
var tokenResult = await TokenProvider.RequestAccessToken();
if (tokenResult.TryGetToken(out var token))
{
requestMessage.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", token.Value);
var response = await Http.SendAsync(requestMessage);
}
Program.cs
builder.Services.AddOidcAuthentication(options =>
{
builder.Configuration.Bind("Local", options.ProviderOptions);
options.ProviderOptions.DefaultScopes.Add("email");
});
Any ideas? Is a scope missing? I can see id_token in Session storage... Perhaps any net 5 example of Blazor WASM and core web api?
Edit:
I see there is a network call made by RequestAccessToken to google auth, like if it were trying to authenticate again
Create a WebAssembly Blazor App standalone with individual accounts.
Replace the content in the appsettings.json file with the following code:
{
"Google": {
"Authority": "https://accounts.google.com/",
"ClientId": "11111111111-11111111111111111111111111111111.apps.googleusercontent.com",
"DefaultScopes": [ "email" ], // The Blazor WebAssembly template automatically configures default scopes for openid and profile
"PostLogoutRedirectUri": "https://localhost:44313/authentication/logout-callback",
"RedirectUri": "https://localhost:44313/authentication/login-callback",
"ResponseType": "id_token token"
}
}
Run your app, and click on the Login link...You're being redirected to Google' Login page. Authenticate with Google...You are being redirected to your app, the Login is changed into Logout, and your user name appears near it.
You may view the id_token and profile via the developers' tools.
How to retrieve the access token ?
Add the following code snippet to your Index page and run...
#page "/"
#using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
#inject IAccessTokenProvider TokenProvider
<p>#output</p>
<button #onclick="DisplayToken">Display Access Token </button>
#code
{
private string output;
private async Task DisplayToken()
{
var tokenResult = await TokenProvider.RequestAccessToken();
if (tokenResult.TryGetToken(out var token))
{
output = token.Value;
}
}
}
Note: The code above is for demonstration purposes only (following your code sample). However, if you perform an HTTP call to your Web Api using the HttpClient service the access token is automatically retrieved and assigned to the Authorization header by the AuthorizationMessagelHandler object.
I have created a unity application to sign-in using google and access google-classroom api. The sign-in is successful and the scope allows access to the courses too.
Question:
How to query the google classroom api after signing in with firebase.
endpoint : https://classroom.googleapis.com/v1/courses/105459102203
Method : GET
Parameter : CourseId which I already have
BearerToken : How to retrieve this from firebase?
When I try using auth-code and/or idToken it gives the following error:
{
"error": {
"code": 401,
"message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
}
Thanks in advance.
There are many ways to make a succesfully API request via firebase Auth, in particulary to Google Classroom API:
The hard way is to create a HttpInterceptor for the firebase.UserCredentials and pass it on headers of every HttpRequest, somethis like this:
headers: new HttpHeaders(
{
'Content-Type': 'application/json',
Authorization: `Bearer [${this.user$.AccessToken}]`
})
this is what I call the hard way because you have to ensure to pass and refresh tokens y every API services.
Use the javascript library "gapi" to login the client, and then use the token response as credential to login in Firebase. This aproach creates a pure OAuth2 login that serves to Firebase and further Google APIs requests, as follows:
declare var gapi;
/** Initialize Google API Client */
initClient(): void {
gapi.client.init({
apiKey: environment.firebaseConfig.apiKey,
clientId: environment.firebaseConfig.clientId,
discoveryDocs: environment.firebaseConfig.discoveryDocs,
scope: environment.firebaseConfig.scope,
});
}
/** Do a OAuth login and then pass it to a FirebaseAuth service */
async login() {
const googleAuth = gapi.auth2.getAuthInstance();
const googleUser = await googleAuth.signIn();
const token = googleUser.getAuthResponse().id_token;
const credential = firebase.auth.GoogleAuthProvider.credential(token);
await this.afAuth().signInAndRetrieveDataWithCredential(credential);
}
/** Then you're ready to make a request*/
/**
* Lists all course names and ids.
* Print the names of the first 10 courses the user has access to. If
* no courses are found an appropriate message is printed.
*/
listCourses() {
this.courses$ =
gapi.client.classroom.courses.list({pageSize=10;}).then(response => {
return from<Course[]>(response.result.courses);
});
}
Am trying to test my web push notification from postman
my app id is thepostman-2018 so I am sending post requests to the url
https://fcm.googleapis.com/v1/projects/thepostman-2018/messages:send
event though I have set Authentication header and passed my Server key
i am getting this response
{
"error": {
"code": 401,
"message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
}
FCM v1 requests do not use the API key from the Firebase console to authorize requests. Instead, they use credentials retrieved by authenticating using the Service Account Key downloaded from the Firebase console. For example, this is how you generate the token using Node.js:
function getAccessToken() {
return new Promise(function(resolve, reject) {
var key = require('./service-account.json');
var jwtClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
SCOPES,
null
);
jwtClient.authorize(function(err, tokens) {
if (err) {
reject(err);
return;
}
resolve(tokens.access_token);
});
});
}
See the guide for more details.
We have an App that uses firebase auth. Now we would like to send the user from the app to our website in order for him to perform some actions.
Is it somehow possible to automatically login the user when he comes from the App? He has already provided his login credentials and we have the auth object from firebase. Can we pass a token or somthing to our website and have the firebase SDK on the site log him automatically?
The common way to do this right now is as follows:
After the user signs in in one website, get the ID token via currentUser.getIdToken()
Post the ID token to your backend to serve the destination website.
On your backend, using Admin SDK, get the ID token, verify it, check the auth_time to make sure it is a recent login to minimize any window of attack. If everything checks out, mint a custom token via admin sdk createCustomToken.
Return the custom token to the website.
On the client side, sign in with custom token: signInWithCustomToken and the same user is now signed in on the website.
I was able to do this a bit easier, without having my own backend server to create a custom token, as long as you are using Google auth. It might work for other providers but here's how I did it with Google auth on Android:
Android:
activity.startActivityForResult(
googleSignInClient.signInIntent,
object : ActivityWithResultListener.OnActivityResultListener {
override fun onActivityResult(resultCode: Int, data: Intent?) {
if (data != null) {
val credential = GoogleAuthProvider.getCredential(account.idToken!!, null)
idToken = account.idToken!!
// Then pass the token to your webview via a JS interface
}
)
Web:
const idTokenFromApp = AndroidBridge.getAuthToken(); // This is the idToken from the Android code above
if (idTokenFromApp) {
// from https://firebase.google.com/docs/auth/web/google-signin
// Build Firebase credential with the Google ID token.
// https://firebase.google.com/docs/reference/js/v8/firebase.auth.GoogleAuthProvider#static-credential
const credential = firebase.auth.GoogleAuthProvider.credential(idTokenFromApp);
// Sign in with credential from the Google user.
firebase.auth.signInWithCredential(credential).catch((error) => {
// Handle Errors here.
const errorCode = error.code;
const errorMessage = error.message;
logError(`Error logging in: ${errorCode} ${errorMessage} token: ${idTokenFromApp}`, error);
});
}
I'm writing a watchapp for Pebble to show events from the Google calendars.
I'm using Auth 2.0 to authenticate the user as described in this document.
Then I retrieve events using this API v3 call, specifying my access_token in the authorization header.
For the calendars created and managed by the user everything works fine.
However if I try to get the events from the Google+ calendars, such as Birthdays (#contacts#group.v.calendar.google.com) or Holidays in Italy (en.italian#holiday#group.v.calendar.google.com), the answer is 404:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "notFound",
"message": "Not Found"
}
],
"code": 404,
"message": "Not Found"
}
}
What am I doing wrong? Or is it a bug of the Calendar API?
Thanks to luc, here's the answer!
I was calling the service this way:
var GET_EVENT_LIST = "https://www.googleapis.com/calendar/v3/calendars/%s/events";
var calendarId = "#contacts#group.v.calendar.google.com";
var token_type = "Bearer";
var access_token = "...";
var url = sprintf(GET_EVENT_LIST, calendarId);
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.setRequestHeader("Authorization", token_type + " " + access_token);
req.send(null);
I solved changing the fifth line to:
var url = sprintf(GET_EVENT_LIST, encodeURIComponent(calendarId));