Azure Active Directory: how to get user's object id via auth code flow (MSAL)? - azure

I have developed web application (Python/Django) for my client and he wants me to add SSO via Azure Active Directory that he setup. Also I need to fetch user profile information (email, upn) and update it when it changes in AD.
I managed to get SSO working using MSAL with auth code flow and able to send requests to Graph API on behalf of user to get profile information (/me).
To get profile updates I created subscription (webhook) to /users resource using app identity (client credentials grant flow).
The problem is that I can't understand how to correlate users I get from subscriptions with users I get from auth code flow via MSAL. Notifications from subscriptions give me ids i can find on azure portal (GUID), but profile information requests on behalf of user dont give me same ids. There are ids, but these ids are differenet (something like c66b9ba73bcba166)

As juunas mentioned, the object id is typically oid or sub.
Example using jwt.ms to examine the ID token:
Also, if your app needs to distinguish between app-only access tokens and access tokens for users, you can use use the idtyp optional claim.

Related

Docusign integration App not allowing to send cross account documents for eSign. INVALID_USER error

We have done one CRM integration where we as an CRM have our own docusign pro account.
We completed the GoLive process successfully and have all required data like Integration key, Account Id, Client Id and Secret Key for App.
Now this CRM integration will be used as an mediator for our clients who will have their own purchased docusign accounts.
So till now we have 2 accounts,
CRM Integration docusign account with GoLive status.
Client account to send their own documents for eSign through our CRM integration.
What we have achieved till now?
We completed the consent flow where we redirect our clients to docusign consent page where they provide consent to our app by login into their docusign account. In this flow we use CRM integration account id in URL which takes our client for consent page. On confirm the client will be redirected back to CRM with auth code attached in redirect URL.
We use this auth code to get access token for this client. We use CRMs account id, Integration App secret key and clients auth code to get the access token. We are successful in this too. We get clients access token. No Issues.
Now when our client is trying to send a document for eSign using the access token received in step 2 above, the docusign throws an error saying INVALID_USER.
I have referred to this post Simillar Issue it kind of approves of what we are trying to achieve but it is failing with error.
Let me try to explain and make sure it's clear.
The IK (Integration Key) is global for the entire environment. By environment I mean either the developer environment, or the production environment. When you went live and completed the process using a production environment - you made your IK available for any account and any user in the production environment.
Now, when you get an access token to make API calls, this token is for a specific userId. The userId can be a member of one ore more accounts as showed in this diagram:
The userId is provided by the user logging in when given the option to consent. So when you doing your consent flow, there's a web browser and user that logs in, that is the userId that consent.
Separately, when you request a token using JWT grant, you provide a userId, that userId is a GUID for a unique user in the system.
This GUID must be for the same exact production user that gave consent. That's first thing to confirm.
Now, if you already have an access token to make API calls, when you make a specific API call, you need to provide an accountID. That's another GUID representing an account, not a user. The userId that was provided to the JWT Grant flow must represent a user that has a membership (it is a member of) in the account for which you provided a GUID (a user can be a member of more than one account). That is the second thing to check.
Lastly, there's a baseURI that is used to make API calls and it can be different for different accounts. You need to also confirm you are using the correct one.

Web app with Azure AD SSO: Is it possible to give users from an external tenant access to their email?

I have an application registered in Azure Active Directory. I use this app registration to provide a simple SSO implementation for my web application. Users go to my application, choose SSO for authentication, redirect to the login.microsoft.com page, then get sent back with the proper codes. No sweat.
The SSO part is not issue inside or outside of my tenant. I've been able to get the proper flow setup and if users are permitted access, they can login with their Microsoft account and access my application.
Email, however, is turning out to be a real issue.
Internal users in my tenant are not a problem at all. Once I get the JWT from Microsoft, I can request an access token for Graph, send emails, create drafts, delete, etc. There is no issue here.
The problem comes up when I have a user in an external tenant. They can login just fine and get a code from Microsoft, but email doesn't work. I started researching a multitenant solution with the Graph API and made some progress there. I was able to change how they request their tokens using 'client_credentials' and got the appropriate delegated app permissions set up but those permissions allow the external tenant to send emails as though they were users in my tenant. Which obviously I don't want.
I have the external users setup as guest users in my tenant. I've even gone so far as to put an Exchange Online license on the guest users account.
This is the latest error I've received:
[error] => Array
(
[code] => ResourceNotFound
[message] => Resource could not be discovered.
[innerError] => Array
(
[date] => 2021-08-09T16:08:41
[request-id] => 76d9c8ad-e2fd-4286-a8d7-5a3bb4ff3ba8
[client-request-id] => 76d9c8ad-e2fd-4286-a8d7-5a3bb4ff3ba8
)
)
I get this when I put the external user's object ID in the request for the sendMail method of the Graph API. If I put an internal user's object ID into that request, the external user can login, get a token, and send mail as that internal user just fine.
So my question is, is this even possible? Can a user in an external tenant login to my app using Azure AD SSO and also have access to send mail from their account within my application? If so, how far off base am I with my implementation?
As it is a multi-tenant application that supports SSO for external users.
As per Dev's Comment,
Not sure in your scenario, you're using Azure AD B2C (not sure it suits your scenario) or B2B and try to simulate accessing multiple mailboxes
Identity Providers for External Identities
External Guest users with personal MS Account can redeem your B2B collaboration invitations.
During Self Service sign-up user flow, personal MSA can be added as one of the Identity Provider.
No Additional Configuration required to make this identity provider available for user flows.
Email one-time passcode: When redeeming an invitation or accessing a shared resource, a guest user can request a temporary code, which is sent to their email address. Then they enter this code to continue signing in.
Email one-time passcode feature authenticates B2B guest users when they can't be authenticated through other means.
When setting up a self-service sign-up user flow, you can add Email One-Time Passcode as one of the allowed identity providers.
Reference link:
Identity providers for External Identities - Azure AD | Microsoft Docs
B2B Collaboration - Understand user tokens in B2B collaboration - Azure AD | Microsoft Docs

How do I configure my Azure app registration and native client to support guest accounts using MSA authenticated through device code flow?

I have an application that currently authenticates users in an Azure active directory tenant. I have native clients that use MSAL, device code flow and an api scope to get a token to use with an ASP.NET Web API application. We also have a web front end that consumes the web api endpoints. We would like to allow external users access to this application. I've added guest users with personal Microsoft accounts (MSA) to the tenant and they are able to authenticate to the web front end using MSAL.js in an SPA. When these guest users try to authenticate using device code flow I get the error:
Message: AADSTS165000: Invalid Request: The request did not include the required tokens for the user context. One or more of the user context values (cookies; form fields; headers) were not supplied, every request must include these values and maintain them across a complete single user flow. The request did not return all of the form fields. Failure Reasons:[Token was not provided;]
Regular users on the tenant authenticate using the device code flow successfully.
Authority is : https://login.microsoftonline.com/{my tenant id}
Scope passed for device code is an api scope: api://{my api id}/data.read
In the app registration the redirect URLs are set to :
https://login.microsoftonline.com/common/oauth2/nativeclient and
msal{some id}://auth
Implicit grant is enabled for Access tokens and Id tokens
Supported account types is to to single tenant
Allow public client flows is set to Yes
If I change the authority to use 'common' instead of the tenant id, the guest user can authenticate but then the token I get from the client uses the Microsoft account tenant of 9188040d-6c67-4c5b-b112-36a304b66dad and the OID is for that tenant and not the OID of the guest user in my org's tenant

Cannot get complete signed in user AAD details through the azure graph api

i used https://github.com/Wintellect/node-azure-oauth sample code to authenticate with OAuth2 Against Azure Active Directory and it is working fine O365 user(any domain).
then add https://github.com/fhellwig/azure-graphapi code to call azure graph api to get user group data using the access token.
but it only show my active directory data(application registered directory) not the signed in users data.
i changed multi tenant & application permission configuration options. but didnt success and i use my tenant(ex : abcedf#onmicrosoft.com) to call graph api.
how do i pull signed in users details
If you have an identifier for your user, then you can make the following REST call:
GET graph.windows.net/myorganization/users/#User_Identifier_Here#/memberOf?api-version=1.5
User identifiers can be the user's objectId or the user's user principal name. For an example, if you had the user principal name of the user, the query would be:
GET graph.windows.net/myorganization/users/user#contoso.com/memberOf?api-version=1.5
This is included in the list of queries here:
https://msdn.microsoft.com/en-us/library/azure/jj126255.aspx
Tenant id should belong to end users tenant not the publishers tenant with bearer authorization header
https://graph.windows.net/<tenant id>/table?api-version=1.5

How do I know which users are accessing my API hosted in Azure AD OAuth 2.0 so they only access their private data?

I have developed a Web API, hosted in Azure, with OAuth 2.0 Authorization grant thru Azure AD. I have the token system working, I am able to request an authorization code, and use that to request access/refresh token, and then request data from the API in general.
The next thing I am struggling with is how do I allow user A to access Database A data and user B to access Database B data. We have different databases and each user has their own private data. Both user A and B are using the same native "client" desktop application. So here is my thought process:
We could make user A its own "application" in Azure AD, and user B its own "application" in Azure AD. They would have different access tokens then. But how do I know in my Web API that user A is calling my API, or user B is calling my API if Azure AD is the one doing the authorization? is there a way to extract which particular user is calling the API from which token is used or something, so I can pull data for only that user? All I have currently is the [Authorize] at the top of the ApiController for the different REST calls and then setting up the application in Azure AD, but that is just general authorization access to the API, not specific permission/authenticated access to private user data.
I assume that you are using OWIN/Katana with JWT support for authorization. If so, then you should find that if you get the ClaimsPrincipal.Current property there will be a ClaimsPrincipal object that represents the user that was authenticated. It will contain a set of claims that are returned from AzureAD. You can use those claims to retrieve an identifier for the user and map that to their associated database.
Take a look at the sample here:
https://github.com/AzureADSamples/WebAPI-OnBehalfOf-DotNet
In particular this file:
https://github.com/AzureADSamples/WebAPI-OnBehalfOf-DotNet/blob/master/TodoListService/Controllers/TodoListController.cs
line 80:
// A user's To Do list is keyed off of the NameIdentifier claim, which contains an immutable, unique identifier for the user.
Claim subject = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier);
After this code the subject.Value property will contain an identifier for the authenticated user.
This link contains some documentation on the set of claims that Azure AD will return:
http://msdn.microsoft.com/en-us/library/azure/dn151790.aspx
Search for "Azure AD issues a fixed set of claims for the authenticated users."

Resources