How to get user profile from id_token through API call - api

I have an API that a applications uses, the application sends me a id_token of a already authenticated user or Google accounts.
How can I make a API call (not java script call) in ASP.net to the google API server to get the users profile information such as name, so that I can save the user in the DB for the application.
I already have a google project with a Client ID and client secret.

So I found a way to though asp.net API get the user information that I wanted.
using (var client = new System.Net.WebClient())
{
var uri = new Uri("https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=" + ACCESSTOKENFROMLOGGININ + "&access_type=offline");
var response = client.DownloadString(uri);
}
you response will have these fields
{
"issued_to": "",
"audience": "",
"user_id": "",
"scope": "",
"expires_in": 756,
"email": "",
"verified_email": true,
"access_type": "online"
}
Then you could make another call to get more personal information
var userInfoUri = new Uri("https://www.googleapis.com/oauth2/v2/userinfo");
var userInfoClient = new System.Net.WebClient();
client.Headers.Add("Authorization", "Bearer " + YOUACCESSToken);
and you will receive an object like this
{
"id": "",
"name": "",
"given_name": "",
"family_name": "",
"link": "",
"picture": "",`enter code here`
"locale": "en"
}

Related

Adding Custom Claims To Azure Active Directory Web App Login

I have managed to change my .NET Core 6 Razor Pages app to login using Azure Active Directory by following this
https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-web-app-sign-user-sign-in?tabs=aspnetcore
The trouble is that I need to add some custom claims to the login, the details of which are in the database (SQL Server), and I do not know how to go about that other than to store the claims in memory.
Previously, I used the following code in my login page.
public ActionResult OnPostLogin(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (ModelState.IsValid)
{
if (_userRepository.GetUserValid(Input.Username, Input.Password))
{
var claimsIdentity = new ClaimsIdentity(_loginClaimRepository.ClaimList(Input.Username), CookieAuthenticationDefaults.AuthenticationScheme);
var result = HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity),
new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = new DateTimeOffset(DateTime.UtcNow.AddHours(8)),
AllowRefresh = true
});
if (result.IsCompletedSuccessfully)
{
return LocalRedirect(returnUrl);
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
}
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
}
}
return Page();
}
I wonder if there is a standard way to intercept the login process and add some custom claims?
I registered an app in azure active directory by clicking new registration:
Added the name and clicked on azure register.
Image for reference:
After app registration I go to manifest and updated the app roles.
Image for reference:
added app roles in Json format:
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"description": "Consumer apps have access to delete consumer data.",
"displayName": "webapp Delete role",
"id": "5e491592-0270-40cb-b70d-2f67b3ce0910",
"isEnabled": true,
"value": "webapp.delete"
},
{
"allowedMemberTypes": [
"Application"
],
"description": "Consumer apps have access to update consumer data.",
"displayName": "webapp Update role",
"id": "d7395cab-0ae9-41c1-a5cd-e945afca8465",
"isEnabled": true,
"value": "webapp.update"
},
{
"allowedMemberTypes": [
"Application"
],
"description": "Consumer apps have access to write consumer data.",
"displayName": "webapp Writer role",
"id": "37605316-22ca-4587-8a98-56e31ba1a2b0",
"isEnabled": true,
"value": "webapp.write"
},
{
"allowedMemberTypes": [
"Application"
],
"description": "Consumer apps have access to read consumer data.",
"displayName": "webapp Reader role",
"id": "12eb6844-6ff4-4731-a349-d5f803cfd6c5",
"isEnabled": true,
"value": "webapp.read"
}
],
Image for reference:
Saved the update of manifest by clicking save button.
Set the application Id URI. This value will be used as the Scope parameter when requesting an OAuth token for the Client App.
Image for reference:
In this way we can add custom claims app which is registered in active directory.

Microsoft Graph API - 401 Unauthorized While Creating Chat

I using the graph API v1.0 to create the one-to-One chat,but I found some account get 401 results.I check the Permission from the Api '/me/oauth2PermissionGrants',and I can find the 'Chat.Create' permission.
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#oauth2PermissionGrants",
"value": [
{
"clientId": "9fc4855b-4d7e-443b-a8f0-282690a55a73",
"consentType": "Principal",
"id": "W4XEn35NO0So8CgmkKVacwsSh1fUKDpBhq1AxEmfwg74z92MWfk9ToJPj-kyp8I8",
"principalId": "8cddcff8-f959-4e3d-824f-8fe932a7c23c",
"resourceId": "5787120b-28d4-413a-86ad-40c4499fc20e",
"scope": " offline_access openid profile email User.Read User.ReadWrite User.ReadBasic.All Chat.ReadWrite Chat.Create Presence.Read Presence.Read.All ChatMessage.Read ChatMessage.Send"
},
{
"clientId": "d39356e1-6d20-4d19-ad54-5278e19b94ec",
"consentType": "Principal",
"id": "4VaT0yBtGU2tVFJ44ZuU7AsSh1fUKDpBhq1AxEmfwg74z92MWfk9ToJPj-kyp8I8",
"principalId": "8cddcff8-f959-4e3d-824f-8fe932a7c23c",
"resourceId": "5787120b-28d4-413a-86ad-40c4499fc20e",
"scope": " offline_access openid profile email User.Read User.ReadWrite User.ReadBasic.All Chat.ReadWrite Chat.Create Presence.Read Presence.Read.All ChatMessage.Read ChatMessage.Send"
},
{
"clientId": "c81831d1-608e-43fa-abd4-3a09e523cb3c",
"consentType": "Principal",
"id": "0TEYyI5g-kOr1DoJ5SPLPAsSh1fUKDpBhq1AxEmfwg74z92MWfk9ToJPj-kyp8I8",
"principalId": "8cddcff8-f959-4e3d-824f-8fe932a7c23c",
"resourceId": "5787120b-28d4-413a-86ad-40c4499fc20e",
"scope": " offline_access openid profile email User.Read User.ReadWrite User.ReadBasic.All Chat.ReadWrite Chat.Create Presence.Read Presence.Read.All ChatMessage.Read ChatMessage.Send Files.Read Files.ReadWrite Files.Read.All Files.ReadWrite.All Sites.Read.All Sites.ReadWrite.All"
}
]
}
When I post "https://graph.microsoft.com/v1.0/chats",
set the body like this
{"members":[
{ "user#odata.bind":"https://graph.microsoft.com/v1.0/users('8cddcff8-f959-4e3d-824f-8fe932a7c23c')",
"#odata.type":"#microsoft.graph.aadUserConversationMember",
"roles":["owner"]},
{ "user#odata.bind":"https://graph.microsoft.com/v1.0/users('636f150e-f73c-44d6-be0c-4d543b2b4e5d')",
"#odata.type":"#microsoft.graph.aadUserConversationMember",
"roles":["owner"]
}
],
"chatType":"oneOnOne"
}
It response 401 Authentication failed
{
"error": {
"code": "Unauthorized",
"message": "Authentication failed.",
"innerError": {
"date": "2022-05-17T08:41:05",
"request-id": "de03512e-b97d-4229-b1ce-a73a61ed4f3d",
"client-request-id": "de03512e-b97d-4229-b1ce-a73a61ed4f3d"
}
}
}
When I replace another account's token & teamsUserId and try again ,It returns Ok!
Can you help me check the reason?
First of all check your app id secret and confirm
secondly check that the users you are trying to add have authorized your application.
thirdly check for access token you need scopes and permission according to the token you are sending to the graph
If you are using application token , use default scope and check whether you have added the chat.create application permission else if you are using token on behalf of user you need delegated permission for chat.create application

Question about ASP.NET Core 3 Identity / Identity Server / SPA support for Resource Owner Password Grant Type

As per Authentication and authorization for SPAs, I have created a new SPA with support for API authorization. You can view this on GitHub.
In order to support integration tests, I have added a new client (see appsettings.json) that is allowed the resource owner password grant type:
"SecureSpa.IntegrationTests": {
"Profile": "IdentityServerSPA",
"AllowedGrantTypes": [ "password" ],
"ClientSecrets": [ { "Value": "K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=" } ],
"AllowedScopes": [ "SecureSpaAPI", "openid", "profile" ]
}
Then within WeatherForecastControllerTests.cs, I attempt to request the token as follows:
var response = await client.RequestPasswordTokenAsync(new PasswordTokenRequest
{
Address = disco.TokenEndpoint,
ClientId = "SecureSpa.IntegrationTests",
ClientSecret = "secret",
Scope = "SecureSpaAPI openid profile",
UserName = "demouser#securespa",
Password = "Pass#word1"
});
When running the test, I've tried many different combinations, however the results are usually the same (unauthorized_client). This is the relevant log output from Identity Server:
IdentityServer4.Endpoints.TokenEndpoint: Debug: Start token request.
IdentityServer4.Validation.ClientSecretValidator: Debug: Start client validation
IdentityServer4.Validation.BasicAuthenticationSecretParser: Debug: Start parsing Basic Authentication secret
IdentityServer4.Validation.PostBodySecretParser: Debug: Start parsing for secret in post body
IdentityServer4.Validation.SecretParser: Debug: Parser found secret: PostBodySecretParser
IdentityServer4.Validation.SecretParser: Debug: Secret id found: SecureSpa.IntegrationTests
IdentityServer4.Stores.ValidatingClientStore: Debug: client configuration validation for client SecureSpa.IntegrationTests succeeded.
IdentityServer4.Validation.ClientSecretValidator: Debug: Public Client - skipping secret validation success
IdentityServer4.Validation.ClientSecretValidator: Debug: Client validation success
IdentityServer4.Events.DefaultEventService: Information: {
"Name": "Client Authentication Success",
"Category": "Authentication",
"EventType": "Success",
"Id": 1010,
"ClientId": "SecureSpa.IntegrationTests",
"AuthenticationMethod": "SharedSecret",
"ActivityId": "0HLPN4PPDDMCJ",
"TimeStamp": "2019-09-12T02:10:57Z",
"ProcessId": 28948,
"LocalIpAddress": "unknown",
"RemoteIpAddress": "unknown"
}
IdentityServer4.Validation.TokenRequestValidator: Debug: Start token request validation
IdentityServer4.Validation.TokenRequestValidator: Debug: Start resource owner password token request validation
IdentityServer4.Validation.TokenRequestValidator: Error: Client not authorized for resource owner flow, check the AllowedGrantTypes setting{ client_id = SecureSpa.IntegrationTests }, details: {
"ClientId": "SecureSpa.IntegrationTests",
"ClientName": "SecureSpa.IntegrationTests",
"GrantType": "password",
"Raw": {
"grant_type": "password",
"username": "demouser#securespa",
"password": "***REDACTED***",
"scope": "SecureSpaAPI",
"client_id": "SecureSpa.IntegrationTests",
"client_secret": "***REDACTED***"
}
}
IdentityServer4.Events.DefaultEventService: Information: {
"Name": "Token Issued Failure",
"Category": "Token",
"EventType": "Failure",
"Id": 2001,
"ClientId": "SecureSpa.IntegrationTests",
"ClientName": "SecureSpa.IntegrationTests",
"Endpoint": "Token",
"GrantType": "password",
"Error": "unauthorized_client",
"ActivityId": "0HLPN4PPDDMCJ",
"TimeStamp": "2019-09-12T02:10:57Z",
"ProcessId": 28948,
"LocalIpAddress": "unknown",
"RemoteIpAddress": "unknown"
}
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request finished in 212.96790000000001ms 400 application/json; charset=UTF-8
Is this approach supported? If not, is there an alternative approach that can be used to get the token in order to write integration tests? I'm planning to set up test users along with the test client so that I can test lots of different behaviours.
I continued working on this issue and found that the allowed grant type of password was not being added when the profile is set to IdentityServerSPA. I couldn't see a way to add a client without a profile via appsettings, so I removed the configuration from appsettings and created the clients using this approach:
services.AddIdentityServer()
//.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
options.Clients.AddIdentityServerSPA("SecureSpa", builder =>
{
builder.WithRedirectUri("https://localhost:44307/authentication/login-callback");
builder.WithLogoutRedirectUri("https://localhost:44307/authentication/logout-callback");
});
options.Clients.Add(new Client
{
ClientId = "SecureSpa.IntegrationTests",
AllowedGrantTypes = { GrantType.ResourceOwnerPassword },
ClientSecrets = { new Secret("secret".Sha256()) },
AllowedScopes = { "SecureSpaAPI", "openid", "profile" }
});
});
With that in place my tests now run. You can see the final solution here; https://github.com/JasonGT/SecureSpa/.
Everything works fine, however there seems to be a bug (or feature limitation) within DefaultClientRequestParametersProvider. See the 'GetClientParameters' method - if the specified client does not have an associated profile, an InvalidOperationException is thrown.
Let me know if you need more information.
Just for reference' sake: the code above did not work as-is on my end, it broke the SPA sign-in with a redirect_uri invalid exception.
I had to remove the base url, and then it worked:
builder.WithRedirectUri("/authentication/login-callback");
builder.WithLogoutRedirectUri("/authentication/logout-callback");

Tracking email with SendGrid alike MailGun

I'm studying some email services, as SensdGrid and MailGun.
In MailGun docs I found a really usefull function: https://documentation.mailgun.com/user_manual.html#events
You can simply ask to MailGun API the events triggered, sending also some filters. It is really simple and powerful. Here an example:
using System;
using System.IO;
using RestSharp;
using RestSharp.Authenticators;
public class EventsDateTimeRecipientChunk
{
public static void Main (string[] args)
{
Console.WriteLine (EventsDateTimeRecipient ().Content.ToString ());
}
public static IRestResponse EventsDateTimeRecipient ()
{
RestClient client = new RestClient ();
client.BaseUrl = new Uri ("https://api.mailgun.net/v3");
client.Authenticator =
new HttpBasicAuthenticator ("api",
"YOUR_API_KEY");
RestRequest request = new RestRequest ();
request.AddParameter ("domain", "YOUR_DOMAIN_NAME", ParameterType.UrlSegment);
request.Resource = "{domain}/events";
request.AddParameter ("begin", "Fri, 3 May 2013 09:00:00 -0000");
request.AddParameter ("ascending", "yes");
request.AddParameter ("limit", 25);
request.AddParameter ("pretty", "yes");
request.AddParameter ("recipient", "joe#example.com");
return client.Execute (request);
}
}
and an output sample:
{
"items": [
{
"tags": [],
"timestamp": 1376325780.160809,
"envelope": {
"sender": "me#samples.mailgun.org",
"transport": ""
},
"event": "accepted",
"campaigns": [],
"user-variables": {},
"flags": {
"is-authenticated": true,
"is-test-mode": false
},
"message": {
"headers": {
"to": "user#example.com",
"message-id": "20130812164300.28108.52546#samples.mailgun.org",
"from": "Excited User <me#samples.mailgun.org>",
"subject": "Hello"
},
"attachments": [],
"recipients": [
"user#example.com"
],
"size": 69
},
"recipient": "user#example.com",
"method": "http"
}
],
"paging": {
"next":
"https://api.mailgun.net/v3/samples.mailgun.org/events/W3siY...",
"previous":
"https://api.mailgun.net/v3/samples.mailgun.org/events/Lkawm..."
}
}
Is it possible I can't find the same feature in SendGrid? I'm getting crazy searching in their documents.. I found the webhooks, but it isn't what I need. I only want to see the email status with a http request like MailGun does.
Can you help me?
Hope you figured it out by now,
Yet here's for the future :
You should use the webhooks, as follows:
1 configure the apps: clicktrack, opentrack& .what_you_want_to_tarck.. & eventnotify to true, with Get & activate
2 create a POSTURL using RequestPin,
3 activate the event notification from mail settings in dashboard & check the events you want , when you press the testYourIntegration button, you should get the example post request to the created url.
use this code as described in the official documentation:
string apikey = "......."
sg = sendgrid.SendGridAPIClient(apikey=os.environ.get( apikey ))
to_email = Email("....#gmail.com")
from_email =Email ("....")
subject= '...'
content = Content("text/plain","Trying SendGrid")
mail = Mail(from_email, subject, to_email, content)
response = sg.client.mail.send.post(request_body=mail.get())
Now , go & open or click the email sent by code, to declench the event .., then go back
https://requestb.in/Your_bin_id?inspect
& you should see the notifications after a little while
for more, you can then go to :
https://requestb.in/api/v1/bins/bin_id/requests
do a Get request with code & just parse the JSON

Blogger API - Google Scripts Access Token

I found this code here but I can't figure out where to get this ?
"headers" : { "Authorization" : "Bearer YOUR_ACTIVE_TOKEN"}
I have looked and researched every where but I can't find how to get this "Active Token". Can some one please help me to get this ?
function testBlogger() {
var payload =
{
"kind": "blogger#post",
"blog": {
"id": "YOUR_BLOG_ID"
},
"title": "New post",
"content": "With content..."
};
var options =
{
"method" : "post",
"headers" : { "Authorization" : "Bearer YOUR_ACTIVE_TOKEN"},
"contentType" : "application/json",
"payload" : '{ "kind": "blogger#post", "blog": { "id": "YOUR_BLOG_ID" }, "title": "New post", "content": "With content..." }'
};
try {
var result = UrlFetchApp.fetch(
"https://www.googleapis.com/blogger/v3/blogs/YOUR_BLOG_ID/posts",
options);
Logger.log(result);
} catch (e) {
Logger.log(e);
}
}
It involves a few more steps. You need to include the OAuth2 library in your project, enable the Blogger API in the Google Developers console and also create a new a browser key to get your client ID and secret.
var options =
{
"method" : "post",
"headers" : { "Authorization" : "Bearer " + getService().getAccessToken()},
"contentType" : "application/json",
"payload" : '{ "kind": "blogger#post", "blog": { "id": "YOUR_BLOG_ID" }, "title": "New post", "content": "With content..." }'
};
See: Using Blogger API with Google Apps Script
There are multiple steps required to initially setup the code environment to access OAuth2 APIs. In summary
Add an OAuth2 client library to your script project
Enable the Blogger API in the script project's associated Google Developers Console project
Setup a OAuth service in your script project
Authenticate access to generate the tokens
My blog post details all these steps https://mashe.hawksey.info/2015/10/setting-up-oauth2-access-with-google-apps-script-blogger-api-example/