Azure AD B2C Signin from native app - To sign into this application the account must be added to the directory - azure

I have created a new user in AD B2C tenant using AD Graph API.
{
"accountEnabled": true,
"creationType": "LocalAccount",
"displayName": "Alex Wu",
"passwordProfile": {
"password": "Test#123",
"forceChangePasswordNextLogin": false
},
"signInNames": [
{
"type": "userName",
"value": "Dawn"
},
{
"type": "emailAddress",
"value": "dawn#example.com"
},
{
"type": "mobile",
"value": "96587XXXXX"
}
]
}
I'm trying to login with these credential from the Android native app client using adal4j library. I'm able to login with Mobile number and UserName and I can get the access token. But when I tried to login with the Email Address I'm getting an error "To sign into this application the account must be added to the directory".

AFAIK, the Adal4j library doesn't support the Azure AD B2C flow. You need to implement this flow yourself if you want to use this flow with Java developing.
Please refer the code sample mentioned in this document to interact Azure AD B2C via the protocol you want.
In addition, to test the account login with policy we can run it from the portal like figure below. And based on the test it works well for me to login using the email of Azure AD B2C local account.

Related

How to differentiate between 'local' and 'social' user types after login via Azure AD B2C?

I have a Node.js/Express application that uses Azure AD B2C for authentication.
Currently, two types of users can login:
Local accounts - EXTERNAL users in the Azure AD B2C tenant
Social accounts - INTERNAL users from a single Azure AD tenant
Desired Behaviour
I want to display different frontend user interface elements based on the type of user that has logged in.
Local accounts will be able to call endpoints relevant to EXTERNAL users
Social accounts will be able to call endpoints relevant to INTERNAL users
What is the recommended way to differentiate between who logged in?
I can see that the authToken object that is returned from msal-node's acquireTokenByCode() method is different depending on which type of user logged in.
Should I use a property from the authToken object to differentiate between user types?
If so, which property is the best one to use?
And, so that I can perform relevant UI actions accordingly, is it acceptable to store this value as a cookie in the browser (eg 'user_type': 'EXTERNAL' or 'user_type': 'INTERNAL') using something like js-cookie?
Below is a redacted version of the authToken object that is returned after login.
All values are the same for different users types, unless otherwise specified.
Notably, these two properties are only present after a 'social account' login:
idp_access_token
idp
{
"authority": "https://<my-azure-ad-b2c-tenant>.b2clogin.com/<my-azure-ad-b2c-tenant>.onmicrosoft.com/b2c_1_signin1/",
"uniqueId": "*******", // <-- different for each user, this is the object id of the user as represented in the Azure AD B2C tenant
"tenantId": "",
"scopes":
[
"https://<my-azure-ad-b2c-tenant>.onmicrosoft.com/my-web-app-api/tasks.write", // <-- these are the api permissions granted to my web app
"https://<my-azure-ad-b2c-tenant>.onmicrosoft.com/my-web-app-api/tasks.read" // <-- these are the api permissions granted to my web app
],
"account":
{
"homeAccountId": "***uniqueId***-b2c_1_signin1.<the-directory-id-of-my-azure-ad-b2c-tenant>", // unique id is different for each user
"environment": "<my-azure-ad-b2c-tenant>.b2clogin.com",
"tenantId": "",
"username": "<user-email-address>", // different for each user
"localAccountId": "***uniqueId***", // different for each user
"idTokenClaims":
{
"exp": 1673069519,
"nbf": 1673065919,
"ver": "1.0",
"iss": "https://<my-azure-ad-b2c-tenant>.b2clogin.com/<the-directory-id-of-my-azure-ad-b2c-tenant>/v2.0/",
"sub": "***uniqueId***", // different for each user
"aud": "<the-application/client id of my web app>",
"iat": 1673065919,
"auth_time": 1673065918,
"idp_access_token": "********", // <-- this property is ONLY present in the authToken returned from the SOCIAL login
"idp": "https://login.microsoftonline.com/<the-directory-id-of-my-azure-ad-tenant>/v2.0", // <-- this property is ONLY present in the authToken returned from the SOCIAL login
"emails":
[
"<user-email-address>" // different for each user
],
"tfp": "B2C_1_signin1",
"at_hash": "*******" // different for each user
}
},
"idToken": "*******", // different for each user
"idTokenClaims":
{
"exp": 1673069519,
"nbf": 1673065919,
"ver": "1.0",
"iss": "https://<my-azure-ad-b2c-tenant>.b2clogin.com/<the-directory-id-of-my-azure-ad-b2c-tenant>/v2.0/",
"sub": "***uniqueId***", // different for each user
"aud": "<the-application/client id of my web app>",
"iat": 1673065919,
"auth_time": 1673065918,
"idp_access_token": "********", // <-- this property is ONLY present in the authToken returned from the SOCIAL login
"idp": "https://login.microsoftonline.com/<the-directory-id-of-my-azure-ad-tenant>/v2.0", // <-- this property is ONLY present in the authToken returned from the SOCIAL login
"emails":
[
"<user-email-address>" // different for each user
],
"tfp": "B2C_1_signin1", // different for each user
"at_hash": "*******"
},
"accessToken": "*******", // different for each user
"fromCache": false,
"expiresOn": "2023-01-07T05:31:57.000Z",
"correlationId": "*******", // different for each user
"requestId": "",
"extExpiresOn": "2023-01-07T05:31:57.000Z",
"familyId": "",
"tokenType": "Bearer",
"state": "",
"cloudGraphHostName": "",
"msGraphHost": "",
"fromNativeBroker": false
}
For Reference
For reference, below are the steps I took to:
Enable login from a single Azure AD tenant
Enable Azure AD users to be able to call Graph API in their own tenant
I added a single Azure AD tenant as an Identity Provider by going to:
Azure Portal > Azure AD B2C Tenant > Azure AD B2C > Identity Providers > + New OpenID Connect provider > [ fill in required fields and click 'Save' ]
Detailed steps on adding an Azure AD tenant as an identity provider can be found here:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/identity-provider-azure-ad-single-tenant?pivots=b2c-user-flow#configure-azure-ad-as-an-identity-provider
In the Scope field, I added the scopes that I wanted the Azure AD users to be able to use in their own tenant, i.e:
openid profile User.ReadWrite.All Directory.ReadWrite.All Team.ReadBasic.All TeamSettings.ReadWrite.All
Then I went to the relevant 'user flow' at:
Azure Portal > Azure AD B2C Tenant > Azure AD B2C > User flows > B2C_1_signin1 > Identity providers > [ check the recently added OpenID connect provider ] > [ click 'Save' ]
In order for Azure AD users to be able to make Graph API calls to their own tenant, I did the following to make sure that an idp_token was returned when they logged in - I believe this is essentially an 'access token' for their tenant:
Azure Portal > Azure AD B2C Tenant > Azure AD B2C > User flows > B2C_1_signin1 > Application claims > [ select 'Identity Provider Access Token' ] > [ click 'Save' ]
The idp claim is the one that you are looking for since it will be set of all external providers of the Azure AD B2C tenant.
Note that the idp_access_token claim is present when pass through is enabled but is only supported for OAuth 2.0 providers, so it may be blank for some.

Add app extension attribute in user flow JWT Azure AD B2C

I am working in Azure AD B2C to add custom extensions per application. Theses extensions must be returned in the jwt when the login is requested by the application.
So I create the extension on the app using the graph api
POST https://graph.microsoft.com/v1.0/applications/{{appid}}/extensionProperties
{
"name": "name",
"dataType": "String",
"targetObjects": [
"User"
]
}
Then I associate a value for a specific user
PATCH https://graph.microsoft.com/v1.0/users/{{userid}}
{
"extension_{{appid(without dashes}}_name": "1234"
}
Now I go on the app manifest to add the optional claim.
"optionalClaims": {
"idToken": [
{
"name": "extension_{{appid(without dashes}}_name",
"source": "user",
"essential": true,
"additionalProperties": []
}
],
"accessToken": [
{
"name": "extension_{{appid(without dashes}}_name",
"source": "user",
"essential": true,
"additionalProperties": []
}
],
"saml2Token": []
},
Save but the claim never appear on the jwt token.
I also tried using the answer of this post but didn't work either.
The problem is you’ve used Optional claims setup, which works for AAD but not AAD B2C.
Follow this: https://learn.microsoft.com/en-us/azure/active-directory-b2c/user-flow-custom-attributes?pivots=b2c-user-flow
If you want to select your custom attribute through the Azure Portal - AAD B2C - User Attributes blade, and the attribute was created via Graph API, you have to recreate it in the Portal for it to reconcile.
You would also need to target the b2c-extensions-app AppId when defining the attribute with Graph API.
I tried to reproduce the same in my environment and got the claims successfully
As Jas Suri - MSFT commented, this will only work if you are adding optional claims to Azure AD application.
I created the extension attribute via Graph API like below:
I associated the above extension attribute to a specific user like below:
Please check whether that extension attribute is visible in optional claims UI or not and add like below:
When you check the manifest, it will be added automatically like below:
I generated the JWT token using auth-code flow via Postman like below:
After decoding the JWT token (ID-Token), I got the claims successfully like below:

Can we add a extra claims in Azure AD Groups when we create them via Graph API?

Is it possible to add extra properties to the Azure AD groups when we create them in azure ad b2c via graph api. Just like we do it for users (we can add claims to the user)
I am not able to find any resource for this. let me know if that is possible.
Thanks!
Yes. You could do that.
Find the "b2c-extensions-app" under Azure AD B2C - App registrations (Preview) in Azure AD B2C. It's the app which stores the extension property in Azure AD B2C. Record its object ID.
Use the following call to register an extension in the app above. Reference here.
POST https://graph.windows.net/{your B2C tenant}/applications/<applicationObjectId>/extensionProperties
{
"name": "customAttribute",
"dataType": "String",
"targetObjects": [
"Group"
]
}
Then you will get an extension for Group in the response: extension_{client id of b2c-extensions-app}_customAttribute.
Now create a group with the extension property.
POST https://graph.windows.net/{your B2C tenant}/groups
{
"displayName": "Example Group",
"mailNickname": "ExampleGroup",
"mailEnabled": false,
"securityEnabled": true,
"extension_{client id of b2c-extensions-app}_customAttribute": "customAttribute for group"
}

B2C Custom Attributes not showing when created using Graph API directory schema API

Using the extension API documented here:
https://msdn.microsoft.com/en-us/library/azure/ad/graph/howto/azure-ad-graph-api-directory-schema-extensions
in conjuction with the B2C Graph Client sample:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-devquickstarts-graph-dotnet
I created a custom attribute via the AD Graph API for directory schema extensions using this API:
POST
https://graph.windows.net/contoso.onmicrosoft.com/applications/<applicationObjectId>/extensionProperties?api-version=1.6
{
name: "OrgRoleId",
dataType: "String",
targetObjects: [
"User"
]
}
(Note I changed the API version to 1.6).
The API created custom attributes appear using the B2CGraphClient sample and has the same data as those registered via the Azure portal for B2C.
However, these API created custom attributes don't appear in the Azure portal 'User attributes' blade for the tenant, while those custom attributes created via the Azure portal for the B2C tenant do.
Note that I can successfully read and write these extension values for users (via the Graph API). I just cannot put them into claims because they don't appear on the 'User attributes' blade nor the policy claims blade in the Azure portal, and therefore they are not added as claims to the token.
What I am missing/doing wrong?
Output from B2C.exe Get-extension-attribute <b2c-extensions-app objectId>. *_Test1 appears (portal created), while *_UserRoleId does not (API created):
{
"odata.metadata": "https://graph.windows.net/<tenant_id>/$metadata#directoryObjects/Microsoft.DirectoryServices.ExtensionProperty",
"value": [
{
"odata.type": "Microsoft.DirectoryServices.ExtensionProperty",
"objectType": "ExtensionProperty",
"objectId": "f58bc813-632c-486b-bff1-61695eeab691",
"deletionTimestamp": null,
"appDisplayName": "",
"name": "extension_<object_id>_Test1",
"dataType": "String",
"isSyncedFromOnPremises": false,
"targetObjects": [
"User"
]
},
{
"odata.type": "Microsoft.DirectoryServices.ExtensionProperty",
"objectType": "ExtensionProperty",
"objectId": "5e69b2d9-1ab0-463f-a231-5c188e92b4a1",
"deletionTimestamp": null,
"appDisplayName": "",
"name": "extension_<object_id>_UserRoleId",
"dataType": "String",
"isSyncedFromOnPremises": false,
"targetObjects": [
"User"
]
}
...
When you add an extension attribute through the portal, it is created in the directory and owned by the b2c-extensions-app application and it is also added to a tenant-wide policy. That is what allows you to use them in application policies as you create them.
When you create an extension attribute using Graph API, it is not added to the policy and usually created on an application other than b2c-extensions-app. You can use these properties directly in custom policies, but they will not appear in the portal and cannot be used in the policies created through the portal.
It is a best practice to just create the extension properties through the portal so they are available for all policies. This allows customers to mix and match custom policies with built-in b2c user flows.

How should I get last login timestamp of Azure AD B2C user?

I need to get below details of Azure AD B2C users -
Created Date user account
Last Login
User is Active or De-active
I have explored Azure AD graph API (Get-User) but it throws some exception.
https://learn.microsoft.com/da-dk/azure/active-directory-b2c/active-directory-b2c-devquickstarts-graph-dotnet
Still I am not sure that, above information will get from Azure AD B2C graph API or not.
Is there any other way to get the above Azure AD B2C user details?
The below API will provide the response
'https://graph.microsoft.com/beta/users?$select=displayName,signInActivity
{
"displayName": "test",
"id": "bf7a60-3db4-4943-8d45-a7de9276c"
},
{
"displayName": "Admin",
"id": "ae1f1dd6-886a-484b-b46e-e48cce4",
"signInActivity": "#{lastSignInDateTime=2021-03-15T14:06:21Z; lastSignInRequestId=55909a8c-2c13-4e5a-8e23-8952571a0300}"
},

Resources