I am new to chrome extensions and gmail api's.
I am trying to connect with gmail api's while implementation of my extension.
I have api keys and client id.
In your manifest you first need to add :
"background": {
"scripts": ["background.js" ,"client.js"]
},
"content_security_policy": "script-src https://*.google.com 'unsafe-eval'; object-src 'self'",
"oauth2": {
"client_id": "<your client id>",
"scopes": [
scope: 'https://mail.google.com/'
]
},
"permissions": [
"background",
"identity",
"tabs",
"https://www.googleapis.com/*",
"https://*.googleusercontent.com/*",
"https://mail.google.com/",
],
When client.js is the gmail API library ...
Now in your background page you need to connect..I give you example in JS:
chrome.identity.getAuthToken(
{'interactive': true},
function(token){
/// you can use the token( user token ) for create http request to gmail api
}
);
window.gapi_onload = function(){
gapi.client.setApiKey("<your api code>");
gapi.auth.authorize(
{
client_id: '<Your client id>',
immediate: true,
scope: "https://mail.google.com/",
},
function(){
gapi.client.load('gmail', 'v1', gmailAPILoaded);
}
);
}
function gmailAPILoaded(){
// Do things you want with gapi.client
}
Most of things I give you based on this guide but it's not work for me exectly so I change some things.
Good luck
You do not necessarily need the gapi.auth.authorize(...) calls. Look for the chrome.identity API instead.
Related
Before getting into the issue, let me tell you what I am trying to achieve.
I need to implement sort of SSO in all of my applications. For which I want to use ASP.NET Zero solutions as
SSO Provider as well as Clients.
Is it possible or am I overthinking?
I am using ASP.NET Zero template: ASP.NET Core - MVC & jQuery
I am very new to IdentityServer and OpenId so please excuse for my silly mistakes if I have made.
In one of ABP project, I have added a static client to IdentityServer AppSettings like below.
First project's AppSettings - Hosted application
{
"ClientId": "localhost",
"ClientName": "MVC Client Demo",
"AllowedGrantTypes": [
"implicit"
],
"RequireConsent": "true",
"ClientSecrets": [
{
"Value": "test"
}
],
"RedirectUris": [
"https://localhost:44302/signin-oidc"
],
"PostLogoutRedirectUris": [
"https://localhost:44302/Account/Login"
],
"AllowedScopes": [
"openid",
"profile",
"email",
"phone",
"default-api"
],
"AllowOfflineAccess": "true"
}
Now from my second ABP project (localhost), I am trying to enable OpenId to authenticated through above server.
Second project's AppSettings - Running on localhost
"OpenId": {
"IsEnabled": "true",
"Authority": "https://[applicationname].azurewebsites.net/",
"ClientId": "localhost",
"ClientSecret": "test",
"ValidateIssuer": "true",
"ClaimsMapping": [
{
"claim": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
"key": "http://schemas.microsoft.com/identity/claims/objectidentifier"
}
]
}
However I am not getting any error, in logs I can see there is a message that says:
AuthenticationScheme: Identity.External signed in.
And a cookie is being created with key "Identity.External" but login-is not happening successfully.
Inside AccountController below line returns null and that resulting into unsuccessful login.
**var externalLoginInfo = await _signInManager.GetExternalLoginInfoAsync();**
if (externalLoginInfo == null)
{
Logger.Warn("Could not get information from external login.");
return RedirectToAction(nameof(Login));
}
Try adding
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Add("sub", ClaimTypes.NameIdentifier);
before services.AddAuthentication()
This will map sub claim to NameIdentifier claim so GetExternalLoginInfoAsync will not return null.
I have an Asp.Net Core / ReactJs aopplication. I'm using Microsoft.AspNetCore.ApiAuthorization.IdentityServer to authenticate the API. However, I'm getting an error, which I believe is down to bad configuration.
If I run this locally, with the following config, everything works, and the app redirects to the log-in screen as expected:
"IdentityServer": {
"Clients": {
"MyApp": {
"Profile": "IdentityServerSPA",
}
},
"Key": {
"Type": "File",
"FilePath": "Assets/selfsignedcert.pfx",
"Password": "password"
}
},
However, if I change the config to the following:
"IdentityServer": {
"Clients": {
"MyApp": {
"Profile": "IdentityServerSPA",
"RedirectUri": "https://localhost:5211/authentication/login-callback"
"LogoutUri": "https://localhost:5211/authentication/logout-callback"
}
},
"Key": {
"Type": "File",
"FilePath": "Assets/selfsignedcert.pfx",
"Password": "password"
}
},
It errors (redirecting to the following):
https://localhost:5211/home/error?errorId=1234...
Looking at the auth request, from the client, they are exactly the same; however the second returns an error, while the first successfully redirects.
Is there something wrong with my config? Alternatively, how can I debug this issue?
Both of your Uris in the non-working configuration point to logout. Is this really what you're trying to do?
In the first configuration, you're not defining any Uris, so they will have the following default values:
The redirect_uri defaults to /authentication/login-callback.
The post_logout_redirect_uri defaults to /authentication/logout-callback.
As documented here
Try changing the second configuration to match the default values to see if that helps.
The client configuration of redirect_uri and post_logout_redirect_uri must be identical to the IDP:
redirect_uri: 'https://localhost:5211/authentication/login-callback',
post_logout_redirect_uri: 'https://localhost:5211/authentication/logout-callback',
Or
redirect_uri: $'{IDPhost_config}/authentication/login-callback',
post_logout_redirect_uri: $'{IDPhost_config}/authentication/logout-callback',
I'm trying to setup a solution with the following:
- IdentityServer4 instance
- React / js client
- ASP.NET Core API (protected by IdentityServer)
Since I want to use roles and claims, I would like to use a reference token (id_token) and have the API verify the claims against the IdentityServer.
Configuration for the IdentityServer instance:
"IdentityServer": {
"IdentityResources": [
"openid",
"email",
"phone",
"profile"
],
"ApiResources": [
{
"Name": "b2a6f5a1-9317-4b2f-bb02-c2f7cd70ce9a",
"DisplayName": "My API",
"ApiSecrets": [ { "Value": "<BASE 64 ENCODED SHA256 HASH OF SECRET>" } ]
}
],
"Clients": [
{
"Enabled": true,
"ClientId": "976d5079-f190-41a2-a6f6-be92470bacc0",
"ClientName": "My JS client",
"ClientUri": "http://localhost:3000",
"LogoUri": "logo.png",
"RequireClientSecret": false,
"AllowAccessTokensViaBrowser": true,
"RequireConsent": false,
"ClientClaimsPrefix": null,
"AccessTokenType": "reference",
"AllowedGrantTypes": [ "implicit" ],
"RedirectUris": [ "http://localhost:3000/authentication/login-callback" ],
"PostLogoutRedirectUris": [ "http://localhost:3000/authentication/logout-callback" ],
"AllowedCorsOrigins": [ "http://localhost:3000" ],
"AllowedScopes": [ "openid", "email", "phone", "profile", "b2a6f5a1-9317-4b2f-bb02-c2f7cd70ce9a" ]
}
]
}
Configuration for the (protected) API:
"Identity": {
"Authority": "https://localhost:44311",
"ApiName": "b2a6f5a1-9317-4b2f-bb02-c2f7cd70ce9a",
"ApiSecret": "<UNHASHED SECRET>"
}
Startup.cs for the API:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
})
.AddIdentityServerAuthentication(options =>
{
options.Authority = Configuration.GetValue<string>("Identity:Authority");
options.ApiName = Configuration.GetValue<string>("Identity:ApiName");
options.ApiSecret = Configuration.GetValue<string>("Identity:ApiSecret");
});
I query IdentityServer for an id_token with the following parameters:
export const Settings: any = {
authority: "https://localhost:44311",
post_logout_redirect_uri: "http://localhost:3000/authentication/logout-callback",
redirect_uri: "http://localhost:3000/authentication/login-callback",
response_type: "id_token",
scope: "openid email profile phone b2a6f5a1-9317-4b2f-bb02-c2f7cd70ce9a"
};
I get the following error: Requests for id_token response type only must not include resource scopes.
If I change the scope to:
export const Settings: any = {
// ...
scope: "openid email profile phone" // removed (protected) api resource
};
it works and I get an id_token like this:
{
"nbf": 1573798909,
"exp": 1573799209,
"iss": "https://localhost:44311",
"aud": "976d5079-f190-41a2-a6f6-be92470bacc0",
"nonce": "d768a177af684324b30ba73116a0ae79",
"iat": 1573798909,
"s_hash": "HbWErYNKpgsiOIO82IiReA",
"sid": "vVWVhLnVLiCMdLSBWnVUQA",
"sub": "90f84a26-f756-4923-9d26-6104eef031ac",
"auth_time": 1573798909,
"idp": "local",
"preferred_username": "noreply",
"name": "noreply",
"email": "noreply#example.com",
"email_verified": false,
"amr": [
"pwd"
]
}
Note that the audience is 976d5079-f190-41a2-a6f6-be92470bacc0, which is the js client.
When I use this token on the protected API, it says:
Bearer error="invalid_token", error_description="The audience '976d5079-f190-41a2-a6f6-be92470bacc0' is invalid"
which is not that strange since the API has the id b2a6f5a1-9317-4b2f-bb02-c2f7cd70ce9a.
So my question is: Where am I wrong? How do I get the token for the correct audience?
The ID token will be validated by your client app (React/js) app to get user claims , so the audience is your client app's client ID . A token passe to your web api should be validated by web api , so the audience is web api's name .
The ID token contains information about an End-User which is not used to access protected resource , while Access token allows access to certain defined server resources .You can set response_type to id_token token , and add api name/scope to scope configuration . With implicit flow , after authentication , client will get one ID token and one Access token , you can now use access token to access the protected web api .
I have created app registration in azure aad. I want to add a app role using Microsoft Graph API programmatic.
It seems that there is no Microsoft Graph API to do that. If Azure AD graph is acceptable, you use the following rest API to do that.
PATCH https://graph.windows.net/{tenantId}/directoryObjects/{objectId}/Microsoft.DirectoryServices.Application?api-version=1.6
Note: objectId not applicationId, we could get it from Azure portal.
The following is the test body
appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "SurveyAdmin",
"id": "c20e145e-5459-4a6c-a074-b942bbd4cfe1",
"isEnabled": true,
"description": "Administrators can manage the Surveys in their tenant",
"value": "SurveyAdmin"
}
]
Test result:
We also could check it in the application manifest from Azure portal.
According to my experience, I added appRoles with the help of MicrosoftGraphAPI. You can use this:
respond = "https://graph.microsoft.com/v1.0/applications/{apps-Object-ID}"
request_body = json.dumps({
"appRoles": [ {
"allowedMemberTypes": ['User'],
'description': 'access',
'displayName': 'access',
'id': "XXXX-XXXX-XXX",
"isEnabled": "true",
"value": "null",
"origin": "Application"
}
]
})
response = requests.patch(respond, headers, request_body)
And don't forget to import json and requests
I am working on a music application, with genres & subgenres.
We use loopback for the backend, and angularJS for the frontend with cordova & ionic.
I cannot manage to authorize via ACL a request that looks like Genre/:id/Subgenre, for which I have a proprety automatically made via lb-service.js : Genre.subGenre()
The relation's type is "hasAndBelongsToMany" for both models Genre & Sub-genres.
Here is my angular controller that I use in the frontend to do the API request :
$scope.genres = [];
Genre.find().$promise.then(function(res) { //this request works : goes to GET /Genres endpoint
$scope.genres = res;
$scope.genres.forEach(function(genre) {
genre.checked=false;
genre.subgenres = [];
Genre.subGenres({id: genre.id}).$promise.then(function(r){ //it is this one that doesn't work, GET /Genres/:id/SubGenre endpoint
genre.subgenres = r;
genre.subgenres.forEach(function(s){
s.checked=false;
});
});
});
});
here is the code in lb-service.js that provide the Genre.subGenre() property:
// INTERNAL. Use SubGenre.genres() instead.
"prototype$__get__genres": {
isArray: true,
url: urlBase + "/SubGenres/:id/genres",
method: "GET"
},
and here is the code in the genre model to authorize the acces to the API for the Genre.subGenre() property :
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
},
{
"accessType": "EXECUTE",
"principalType": "ROLE",
"principalId": "$authenticated",
"permission": "ALLOW",
"property": "subGenres" // this is to authorize Genre.subGenre(), doesn't works => 401 error.
},
{
"accessType": "EXECUTE",
"principalType": "ROLE",
"principalId": "$authenticated",
"permission": "ALLOW",
"property": "find" // this is to authorize Genre.find(), it works
}
It looks like it is the property that is not correct, because when I do the same thing to authorize the Genre.find() request, it works.
Thank you a lot for your help.
Actually I figured out that I just needed to change in the ACL :
"accessType": "EXECUTE"
into
'"accessType": "READ"