Microsoft Graph API Endpoint Adds Last Successful Sign-In Date Time
Table of Contents
Previously, if you wanted to find a user’s last successful sign-in to your Microsoft 365 tenant using the Microsoft Graph REST API, you would have to iterate through Entra ID sign-in logs. With new recent additions to the Microsoft Graph API Beta Endpoint, you can now return the UTC value just by parsing the user details and properties. The Microsoft documentation regarding the signInActivity resource type can be found here.
LastSignInDateTime vs LastSuccessfulSignInDateTime
The difference between lastSignInDateTime and lastSuccessfulSignInDateTime property is:
- lastSignInDateTime: The last interactive sign-in date and time for a specific user. You can use this field to calculate the last time a user attempted to sign into the directory the directory with an interactive authentication method. This field can be used to build reports, such as inactive users. The timestamp represents date and time information using ISO 8601 format and is always in UTC time. For example, midnight UTC on Jan 1, 2014 is:
'2014-01-01T00:00:00Z'
. Microsoft Entra ID maintains interactive sign-ins going back to April 2020. - lastSuccessfulSignInDateTime: The datetime of the user’s most recent successful sign in activity.
Other Properties Available Under the Resource Type
The other properties are also currently available under the resource type:
- lastSignInDateTime
- lastSignInRequestID
- lastNonInteractiveSignInDateTime
- lastNonInteractiveSignInRequestId
- lastSuccessfulSignInDateTime
- lastSuccessfulSignInRequestID
Conditions and Limitations
- Details for this property require a Microsoft Entra ID P1 or P2 license and the AuditLog.Read.All permission.
- This property is not returned for a user who has never signed in or last signed in before April 2020.
- Returned only on
$select
. Supports$filter
(eq
,ne
,not
,ge
,le
) but not with any other filterable properties. LastSuccessfulSignInDateTime
is currently only available in the beta endpoint at the time of writing.
In regard to the $select
statement, if you were to query your user in the API using the following code, you will see that it does not return any signInActivity
data.
$apiUrl = 'https://graph.microsoft.com/beta/users/5bcffade-2afd-48a2-8096-390a9090555c'
$Data = Invoke-RestMethod -Headers @{Authorization = "Bearer $($Tokenresponse.access_token)"} -Uri $apiUrl -Method Get
$data
## Results
<#
@odata.context : https://graph.microsoft.com/beta/$metadata#users/$entity
id : 5bcffade-2afd-48a2-8096-390a9090555c
deletedDateTime :
accountEnabled : True
ageGroup :
businessPhones : {6305556528}
city : Geneva
createdDateTime : 9/20/2017 4:21:43AM
creationType :
companyName : The Lazy Administrator
consentProvidedForMinor :
country : United States
department : IT
displayName : Bradley Wyatt
employeeId :
employeeHireDate :
employeeLeaveDateTime :
employeeType :
faxNumber :
givenName : Bradley
imAddresses : {[email protected]}
infoCatalogs : {}
isLicenseReconciliationNeeded : False
isManagementRestricted :
isResourceAccount :
jobTitle : Manager of the Cool Kids
legalAgeGroupClassification :
mail : [email protected]
mailNickname : brad
mobilePhone :
onPremisesDistinguishedName :
officeLocation : Corner Office Duh
onPremisesDomainName :
onPremisesImmutableId :
onPremisesLastSyncDateTime :
onPremisesObjectIdentifier :
onPremisesSecurityIdentifier :
onPremisesSamAccountName :
onPremisesSyncEnabled :
onPremisesUserPrincipalName :
otherMails : {}
passwordPolicies : DisablePasswordExpiration
postalCode : 60134
preferredDataLocation :
preferredLanguage : en-US
proxyAddresses : {SMTP:[email protected], smtp:[email protected]}
refreshTokensValidFromDateTime : 8/26/2020 2:14:57PM
securityIdentifier : S-1-12-1-1540356830-1218587389-171546240-1549111440
showInAddressList :
signInSessionsValidFromDateTime : 8/26/2020 2:14:57PM
state : Illinois
streetAddress : 123 Fake Street
surname : Wyatt
usageLocation : US
userPrincipalName : [email protected]
externalUserConvertedOn :
externalUserState :
externalUserStateChangeDateTime :
userType : Member
employeeOrgData :
passwordProfile :
assignedLicenses : {@{disabledPlans=System.Object[]; skuId=cbdc14ab-d96c-4c30-b9f4-6ada7cdc1d46}}
authorizationInfo : @{certificateUserIds=System.Object[]}
cloudRealtimeCommunicationInfo : @{isSipEnabled=True}
deviceKeys : {@{deviceId=8cd46cd2-3123-4bb1-a262-c75fce0ea538; keyMaterial=UlNBMQAIAAADAAAAAAEAAAAAAAAAAAAAAQABwiWermA4yh+cd4Qyq3N133M9+fsbCZ
identities : {@{signInType=userPrincipalName; issuer=bwya77.onmicrosoft.com; [email protected]}}
onPremisesProvisioningErrors : {}
serviceProvisioningErrors : {}
#>
However, when using the following code with the $select
statement, we are returned the proper data.
$apiUrl = 'https://graph.microsoft.com/beta/users/5bcffade-2afd-48a2-8096-390a9090555c?$select=signInActivity'
$Data = Invoke-RestMethod -Headers @{Authorization = "Bearer $($Tokenresponse.access_token)"} -Uri $apiUrl -Method Get
$data.signInActivity
## Results
<#
lastSignInDateTime : 12/9/2023 4:34:35AM
lastSignInRequestId : edb253e1-bd6b-4396-bda4-0295e3044900
lastNonInteractiveSignInDateTime : 12/9/2023 10:56:08AM
lastNonInteractiveSignInRequestId : dabfdf4c-b63c-421f-b9b5-33b7907f1a00
lastSuccessfulSignInDateTime : 12/9/2023 10:56:08AM
lastSuccessfulSignInRequestId : dabfdf4c-b63c-421f-b9b5-33b7907f1a00
#>
Converting the DateTime Object to Local Time
As mentioned earlier, the datetime objects are always returned using UTC time. We can convert that to our local time zone. Below, I am converting the returned datetime object to Central Standard Time (the time zone I am located in)
$apiUrl = 'https://graph.microsoft.com/beta/users/5bcffade-2afd-48a2-8096-390a9090555c?$select=signInActivity'
$Data = Invoke-RestMethod -Headers @{Authorization = "Bearer $($Tokenresponse.access_token)"} -Uri $apiUrl -Method Get
$lastSignInDateTimeCST = [TimeZoneInfo]::ConvertTimeBySystemTimeZoneId($data.signInActivity.lastSignInDateTime, 'Central Standard Time')
$data.signInActivity | Select-Object -Property lastSuccessfulSignInDateTime, @{Name = 'Last Sign In (CST)'; Expression = {$lastSignInDateTimeCST}}
Then using Select-Object, I can select my new property and value.
$apiUrl = 'https://graph.microsoft.com/beta/users/5bcffade-2afd-48a2-8096-390a9090555c?$select=signInActivity'
$Data = Invoke-RestMethod -Headers @{Authorization = "Bearer $($Tokenresponse.access_token)"} -Uri $apiUrl -Method Get
$lastSignInDateTimeCST = [TimeZoneInfo]::ConvertTimeBySystemTimeZoneId($data.signInActivity.lastSignInDateTime, 'Central Standard Time')
$data.signInActivity | Select-Object -Property lastSuccessfulSignInDateTime, @{Name = 'Last Sign In (CST)'; Expression = {$lastSignInDateTimeCST}}
The returned object is shown below:
lastSuccessfulSignInDateTime Last Sign In (CST)
---------------------------- ------------------
12/9/2023 2:48:58PM 12/8/2023 10:34:35PM
Getting All Users Last Successful Sign-In Date Time
O365 IT Pro’s have posted on GitHub a great script that will iterate through all of your users and not only return their LastSuccessfulSignInDateTime
and LastSignIn
, but also the days since the last successful sign in and last sign in.
My name is Bradley Wyatt; I am a 5x Microsoft Most Valuable Professional (MVP) in Microsoft Azure and Microsoft 365. I have given talks at many different conferences, user groups, and companies throughout the United States, ranging from PowerShell to DevOps Security best practices, and I am the 2022 North American Outstanding Contribution to the Microsoft Community winner.
3 thoughts on “Microsoft Graph API Endpoint Adds Last Successful Sign-In Date Time”
Thanks for the hint!
Is there also the possibility so filter the Sign-In‘s by application, so you can see a user never logged in to Exchange but to SPO?
Thank you. I have been digging through documentation trying to get last sign in date, but couldn’t find a straight forward way to get at it. I was requesting auditlog directly. While it has much more granularity, it isn’t very efficient. Thanks for the article, you saved my bacon!