To display the current user name in an SPFx web part, read this.context.pageContext.user.displayName. SharePoint loads it with the page, so you don’t need an API call, a library or a permission. Here’s the shortest version:
import { escape } from '@microsoft/sp-lodash-subset';
// In render(): no API call, no permission
const name: string = this.context.pageContext.user.displayName;
this.domElement.innerHTML = `<h2>Welcome, ${escape(name)}!</h2>`;
On my SPGuides site that prints “Welcome, Bijay Kumar [Microsoft MVP]!” the moment the web part renders. The same object also gives you the email and login name.
In this tutorial, we’ll display the current user name in an SPFx web part three ways: page context, SharePoint REST with SPHttpClient, and Microsoft Graph /me for job title and photo. Every file of the tested React web part is below.
| Tested with | Version |
|---|---|
| SharePoint Framework | 1.23.2 (Heft toolchain) |
| Node.js | 22 LTS |
| React / Fluent UI | 17.0.1 / @fluentui/react 8 |
| Microsoft Graph client | MSGraphClientV3 (@microsoft/sp-http) |
What does this.context.pageContext.user return?
pageContext.user is an SPUser object. Every web part and extension gets it through this.context, the same way it gets the site URL. If you’re new to web parts, start with building your first SPFx web part.
| Property | What you get | My value |
|---|---|---|
| displayName | The user’s display name | Bijay Kumar [Microsoft MVP] |
| The user’s email address | My work address (blurred in the shots) | |
| loginName | The sign-in name (UPN) | Same address as email |
| isAnonymousGuestUser | true for anonymous sharing-link visitors | false |
| isExternalGuestUser | true for B2B guests | false |
That’s everything a “Welcome, user” banner needs. For an ID, site admin flag, job title or photo, you need one of the two methods further down.
Build the Welcome web part step by step
I built the full web part in VS Code. If Node.js 22 and the tools aren’t installed yet, follow the SPFx development environment setup with Heft first.
1. Create the project. Run these commands in the VS Code terminal. The yo answers create a React web part for SharePoint Online:
yo @microsoft/sharepoint --solution-name spg-current-user --component-type webpart --component-name CurrentUser --framework react --environment spo
cd spg-current-user
npm install
npm install @microsoft/sp-http@1.23.2 --save-exact
@microsoft/sp-http brings SPHttpClient and MSGraphClientV3. Fluent UI 8 ships with the React template. If npm stops with EPERM errors, see fixing npm install errors in SPFx.
2. Add the files. I keep the three data calls in one service class, so the React component only renders:
src/webparts/currentUser/
models/ICurrentUserInfo.ts <- the three result shapes
services/CurrentUserService.ts <- pageContext, SPHttpClient, Graph
components/ICurrentUserProps.ts
components/CurrentUser.tsx <- Welcome banner + details tables
components/CurrentUser.module.scss
CurrentUserWebPart.ts <- creates the service, property pane toggle

3. Create the models file at src/webparts/currentUser/models/ICurrentUserInfo.ts:
// 1. From this.context.pageContext.user (no API call)
export interface IPageContextUser {
displayName: string;
email: string;
loginName: string;
isAnonymousGuestUser: boolean;
isExternalGuestUser: boolean;
}
// 2. From SharePoint REST: _api/web/currentuser (SPHttpClient)
export interface ISharePointUser {
Id: number;
Title: string;
Email: string;
LoginName: string;
IsSiteAdmin: boolean;
}
// 3. From Microsoft Graph: /me (MSGraphClientV3, User.Read); empty fields can come back as null
export interface IGraphUser {
displayName: string;
jobTitle?: string;
department?: string;
officeLocation?: string;
mail?: string;
photoUrl?: string; // blob: URL, undefined when the user has no photo
}
Each interface matches one source. The property names copy what SharePoint and Graph send back, so the JSON maps straight onto them.
4. Create the service at src/webparts/currentUser/services/CurrentUserService.ts:
import { WebPartContext } from '@microsoft/sp-webpart-base';
import { SPHttpClient, SPHttpClientResponse, MSGraphClientV3 } from '@microsoft/sp-http';
import type { ResponseType } from '@microsoft/microsoft-graph-client';
import { IPageContextUser, ISharePointUser, IGraphUser } from '../models/ICurrentUserInfo';
export class CurrentUserService {
constructor(private context: WebPartContext) {}
// 1. Page context: already loaded with the page, so no request and no permission
public getPageContextUser(): IPageContextUser {
const user = this.context.pageContext.user;
return {
displayName: user.displayName,
email: user.email,
loginName: user.loginName,
isAnonymousGuestUser: user.isAnonymousGuestUser,
isExternalGuestUser: user.isExternalGuestUser
};
}
// 2. SharePoint REST: SPHttpClient sends the request as the signed-in user
public async getSharePointUser(): Promise<ISharePointUser> {
const url: string = this.context.pageContext.web.absoluteUrl +
'/_api/web/currentuser?$select=Id,Title,Email,LoginName,IsSiteAdmin';
const response: SPHttpClientResponse =
await this.context.spHttpClient.get(url, SPHttpClient.configurations.v1);
if (!response.ok) {
throw new Error(`SharePoint returned ${response.status} ${response.statusText}`);
}
return response.json();
}
// 3. Microsoft Graph /me: needs the delegated User.Read permission
public async getGraphUser(): Promise<IGraphUser> {
const client: MSGraphClientV3 = await this.context.msGraphClientFactory.getClient('3');
const me: IGraphUser = await client
.api('/me')
.select('displayName,jobTitle,department,officeLocation,mail')
.get();
try {
// 96x96 photo as binary; Graph returns 404 when the user has no photo
const photo: Blob = await client.api('/me/photos/96x96/$value').responseType('blob' as ResponseType).get();
me.photoUrl = URL.createObjectURL(photo);
} catch {
me.photoUrl = undefined;
}
return me;
}
}

getPageContextUser() just copies five properties. The other two methods make real requests, and the next sections explain them.
Get the current user with SPHttpClient (_api/web/currentuser)
getSharePointUser() calls the SharePoint REST endpoint for the signed-in user. You can paste the URL into the browser first to see the raw answer:
https://spguides.sharepoint.com/sites/SPGuides/_api/web/currentuser?$select=Id,Title,Email,LoginName,IsSiteAdmin
this.context.spHttpClient is ready on every web part. It sends the request with the current user’s credentials, because it includes the SharePoint authentication cookies. A plain HttpClient doesn’t, and you’d get 401 Unauthorized.
So the REST call never sees more than the reader can see. There’s no app identity and no admin approval involved. It’s the code version of the [Me] filter in a list view filtered by the current user.
It returns things page context doesn’t: the user’s Id in this site collection and IsSiteAdmin. That ID is what Person columns store, which helps when you filter SharePoint list items in SPFx by the current user.
SharePoint REST API: get the current user, user ID, or a user by email
Outside SPFx, you can call the same endpoints from the browser, the DevTools console or any signed-in script (SharePoint REST API basics covers the setup). /_api/web/currentuser returns the signed-in user, and $select trims it to the fields you need:
GET https://spguides.sharepoint.com/sites/SPGuides/_api/web/currentuser?$select=Id,Title,Email,LoginName
Accept: application/json;odata=nometadata
Here’s the trimmed response from my test on the SPGuides site (account values swapped for the demo admin):
{
"Id": 25,
"LoginName": "i:0#.f|membership|admin@spguides.onmicrosoft.com",
"Title": "SPGuides Admin",
"Email": "Admin@spguides.onmicrosoft.com"
}
Id is the user’s ID in this site collection, so the same person can have a different ID on another site. LoginName comes back in claims format, unlike pageContext.user.loginName, which gave me the plain address.
Without $select, you also get IsSiteAdmin, PrincipalType, UserPrincipalName, IsHiddenInUI, Expiration and a UserId object.
Get a SharePoint user by ID
When a Person column gives you a number, such as AuthorId, turn it into a name with getuserbyid:
GET https://spguides.sharepoint.com/sites/SPGuides/_api/web/getuserbyid(25)?$select=Id,Title,Email,LoginName
It returns the same four fields as above. An ID that doesn’t exist in the site returns 404 with "User cannot be found.", so check the status before you read the body.
Get a user by email or display name
There’s no get-by-email method on web, so filter the siteusers collection instead. The result is an array, even for one match:
GET https://spguides.sharepoint.com/sites/SPGuides/_api/web/siteusers?$filter=Email eq 'Admin@spguides.onmicrosoft.com'&$select=Id,Title,Email
{
"value": [
{ "Id": 25, "Title": "SPGuides Admin", "Email": "Admin@spguides.onmicrosoft.com" }
]
}
Watch the letter case. In my test, the same filter with the address in all lowercase returned an empty value array, because the stored email had a capital letter. Copy the exact value or search by login name.
For a display name, use $filter=Title eq 'SPGuides Admin', or substringof('Admin',Title) for a partial match. Remember that siteusers only holds people who’ve visited or been added to this site.
Here’s the console version you can paste on any page of the site:
const site = "https://spguides.sharepoint.com/sites/SPGuides";
const res = await fetch(`${site}/_api/web/currentuser?$select=Id,Title,Email`, {
headers: { Accept: "application/json;odata=nometadata" }
});
const me = await res.json();
console.log(me.Id, me.Title, me.Email);
Inside an SPFx web part, use this.context.spHttpClient.get() with the same URLs instead of fetch, as shown in the previous section.
To list other people in the directory instead of only the signed-in user, see get user names from Entra ID with Microsoft Graph.
How do I get user details with the Microsoft Graph API?
For job title, department, office or photo, call Microsoft Graph /me. getGraphUser() gets an MSGraphClientV3 from this.context.msGraphClientFactory.getClient('3'), which handles the token for you.
.select() keeps the response to five properties. department isn’t in the default set, so without $select it wouldn’t come back at all.
The photo is a second request to /me/photos/96x96/$value. It returns binary data, so the code asks for a blob and turns it into a URL with URL.createObjectURL().
Users without a photo get a 404, which the try/catch turns into “No photo”. For more Graph calls from SPFx, see the Microsoft Graph API in SPFx guide.
Request User.Read with webApiPermissionRequests
Graph calls need a delegated permission. User.Read is the least privileged scope for /me, and it also covers your own photo. Add this under solution in config/package-solution.json:
"webApiPermissionRequests": [
{
"resource": "Microsoft Graph",
"scope": "User.Read"
}
],
resource is the API’s display name, and scope is the permission. When the .sppkg is uploaded to the app catalog, SharePoint turns this into a request that an admin approves under Advanced > API access.
Before asking, check what’s already granted. My API access page already lists User.Read for Microsoft Graph with “Pre-authorized by Microsoft: Yes”, so /me worked straight from the workbench without any approval.
Grants go to the SharePoint Online Client Extensibility app and apply to every SPFx solution in the tenant. Your code should still handle a missing grant, which is why Graph errors show in a message bar.
Show “Welcome, user” in the React component
Here’s src/webparts/currentUser/components/ICurrentUserProps.ts:
import { CurrentUserService } from '../services/CurrentUserService';
export interface ICurrentUserProps {
service: CurrentUserService;
showGraph: boolean;
}
And the component, src/webparts/currentUser/components/CurrentUser.tsx:
import * as React from 'react';
import { Persona, PersonaSize, MessageBar, MessageBarType, Spinner } from '@fluentui/react';
import styles from './CurrentUser.module.scss';
import { ICurrentUserProps } from './ICurrentUserProps';
import { ISharePointUser, IGraphUser } from '../models/ICurrentUserInfo';
const Row: React.FC<{ label: string; value: string }> = ({ label, value }) => (
<tr><th>{label}</th><td>{value || '-'}</td></tr>
);
const CurrentUser: React.FC<ICurrentUserProps> = ({ service, showGraph }) => {
// 1. Page context: available immediately, no loading state needed
const pageUser = service.getPageContextUser();
const [spUser, setSpUser] = React.useState<ISharePointUser | undefined>();
const [graphUser, setGraphUser] = React.useState<IGraphUser | undefined>();
const [spError, setSpError] = React.useState<string>('');
const [graphError, setGraphError] = React.useState<string>('');
React.useEffect(() => {
// 2. SharePoint REST
service.getSharePointUser().then(setSpUser).catch((e: Error) => setSpError(e.message));
// 3. Microsoft Graph
if (showGraph) {
service.getGraphUser().then(setGraphUser).catch((e: Error) => setGraphError(e.message));
}
}, [service, showGraph]);
// Release the photo blob URL when the web part goes away
React.useEffect(() => () => {
if (graphUser?.photoUrl) URL.revokeObjectURL(graphUser.photoUrl);
}, [graphUser]);
return (
<section className={styles.currentUser}>
<Persona
text={`Welcome, ${pageUser.displayName}!`}
secondaryText={graphUser?.jobTitle}
tertiaryText={graphUser?.officeLocation}
imageUrl={graphUser?.photoUrl}
size={PersonaSize.size72}
/>
<h3>1. this.context.pageContext.user (no API call)</h3>
<table className={styles.details}><tbody>
<Row label="displayName" value={pageUser.displayName} />
<Row label="email" value={pageUser.email} />
<Row label="loginName" value={pageUser.loginName} />
<Row label="isAnonymousGuestUser" value={String(pageUser.isAnonymousGuestUser)} />
<Row label="isExternalGuestUser" value={String(pageUser.isExternalGuestUser)} />
</tbody></table>
<h3>2. SPHttpClient: _api/web/currentuser</h3>
{spError && <MessageBar messageBarType={MessageBarType.error}>{spError}</MessageBar>}
{!spUser && !spError && <Spinner label="Loading SharePoint user..." />}
{spUser && (
<table className={styles.details}><tbody>
<Row label="Id" value={String(spUser.Id)} />
<Row label="Title" value={spUser.Title} />
<Row label="Email" value={spUser.Email} />
<Row label="IsSiteAdmin" value={String(spUser.IsSiteAdmin)} />
</tbody></table>
)}
{showGraph && <h3>3. Microsoft Graph: /me (User.Read)</h3>}
{graphError && <MessageBar messageBarType={MessageBarType.error}>{graphError}</MessageBar>}
{showGraph && !graphUser && !graphError && <Spinner label="Loading Microsoft Graph profile..." />}
{graphUser && (
<table className={styles.details}><tbody>
<Row label="jobTitle" value={graphUser.jobTitle ?? ''} />
<Row label="department" value={graphUser.department ?? ''} />
<Row label="officeLocation" value={graphUser.officeLocation ?? ''} />
<Row label="photo" value={graphUser.photoUrl ? 'Loaded (96x96)' : 'No photo'} />
</tbody></table>
)}
</section>
);
};
export default CurrentUser;
The Fluent UI Persona shows the “Welcome” line right away from page context. Job title, office and photo slot in once Graph answers. More controls are in Fluent UI in SharePoint Framework.
Each source has its own error state, so a Graph 403 never hides the name. The second useEffect releases the photo’s blob URL when the web part unloads.
A little styling for the tables goes in CurrentUser.module.scss:
.currentUser {
padding: 16px;
color: "[theme:bodyText, default: #323130]";
color: var(--bodyText);
h3 {
margin: 20px 0 8px;
font-size: 15px;
font-weight: 600;
}
}
.details {
border-collapse: collapse;
width: 100%;
max-width: 560px;
th,
td {
padding: 6px 10px;
border-bottom: 1px solid #edebe9;
text-align: left;
font-size: 14px;
}
th {
width: 190px;
font-weight: 600;
}
}
Last, the web part file src/webparts/currentUser/CurrentUserWebPart.ts creates the service once and adds a property pane toggle for Graph:
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import { type IPropertyPaneConfiguration, PropertyPaneToggle } from '@microsoft/sp-property-pane';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import { IReadonlyTheme } from '@microsoft/sp-component-base';
import CurrentUser from './components/CurrentUser';
import { ICurrentUserProps } from './components/ICurrentUserProps';
import { CurrentUserService } from './services/CurrentUserService';
export interface ICurrentUserWebPartProps {
showGraph: boolean;
}
export default class CurrentUserWebPart extends BaseClientSideWebPart<ICurrentUserWebPartProps> {
private _service!: CurrentUserService;
protected async onInit(): Promise<void> {
await super.onInit();
// Create the service once; it reuses this.context for every call
this._service = new CurrentUserService(this.context);
}
public render(): void {
const element: React.ReactElement<ICurrentUserProps> = React.createElement(CurrentUser, {
service: this._service,
showGraph: this.properties.showGraph
});
ReactDom.render(element, this.domElement);
}
protected onThemeChanged(currentTheme: IReadonlyTheme | undefined): void {
if (currentTheme?.semanticColors) {
this.domElement.style.setProperty('--bodyText', currentTheme.semanticColors.bodyText || null);
}
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [{
header: { description: 'Current user details' },
groups: [{
groupName: 'Data sources',
groupFields: [
PropertyPaneToggle('showGraph', {
label: 'Load job title and photo from Microsoft Graph',
onText: 'On',
offText: 'Off'
})
]
}]
}]
};
}
}
Turning the toggle off skips the Graph calls entirely, which is handy on a tenant where User.Read isn’t granted. I cover more pane fields in SPFx property pane controls.
In CurrentUserWebPart.manifest.json I set the title, icon and default. More icon options are in configuring the SPFx web part icon:
"title": { "default": "SPG Current User" },
"officeFabricIconFontName": "Contact",
"properties": {
"showGraph": true
}
Test it in the SharePoint workbench with heft start
Older posts used gulp serve. Since SPFx 1.22 it’s heft start; see moving an SPFx project from gulp to Heft. Point it at your site’s workbench in config/serve.json:
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/spfx-serve.schema.json",
"port": 4321,
"https": true,
"initialPage": "https://{tenantDomain}/sites/SPGuides/_layouts/workbench.aspx"
}
Replace {tenantDomain} with your tenant, for example spguides.sharepoint.com. The site workbench matters here, because _api/web/currentuser runs against that site. Then start the dev server:
heft start

The workbench opens and asks Allow debug scripts? Click Load debug scripts, since the code comes from your own localhost. The red SPFx Debug Toolbar then appears at the top.
Hover over the canvas, click the + icon and pick SPG Current User from the toolbox:

The web part shows up right away. The banner comes from page context, and so does the first table. My email and login name are blurred here; both hold my work address.

Scroll down for the two API results. SharePoint returned my site user ID (11) and IsSiteAdmin true. Graph returned Founder as my job title, IT as my department and my photo. officeLocation is empty in my profile, so it shows a dash.

Click the pencil icon to open the property pane. The Graph toggle is on by default. Switch it off and the web part skips both Graph calls:

The hosted workbench was deprecated on 05/13/2026 and retires on 12/01/2026. After that, add the debug query string heft start prints to any modern page and use the SPFx Debug Toolbar.
Package the solution
When it works, stop heft start with Ctrl+C and build the production package:
npm run build
The script runs heft test --clean --production, then heft package-solution --production, and writes sharepoint/solution/spg-current-user.sppkg.

Upload the .sppkg to the app catalog when you’re ready. The User.Read request then appears on the API access page for an admin to review.
Which method should you use?
| pageContext.user | SPHttpClient REST | Microsoft Graph /me | |
|---|---|---|---|
| Request | None | 1 to SharePoint | 1-2 to Graph |
| Permission | None | None (user’s own access) | User.Read |
| Gives you | Name, email, login name, guest flags | Site user ID, IsSiteAdmin | Job title, department, office, photo |
| Best for | Welcome banners | Person column filters, admin checks | Profile cards |
For a plain “Welcome, Megan” greeting, page context is enough. For a full profile card with manager and contact details, see the SPFx user profile web part with Microsoft Graph.
Going from one user to an SPFx employee directory
/me only ever returns the signed-in user. An employee directory lists everyone, which means /users and a broader scope: User.ReadBasic.All (the least privileged) for names, email and photos, or User.Read.All for job titles and full profiles.
Request the smallest one that works and add $top paging, because /users returns 100 users per page by default (999 max). User.Read.All needs an admin to approve it on the API access page.
Building the same kind of personal greeting in a canvas app instead? See getting the current user email in Power Apps.
Common problems and fixes
- Graph returns 403 Forbidden: User.Read isn’t granted in your tenant. Check Advanced > API access and ask an admin to approve the request from your package.
- Photo shows “No photo”: the user never uploaded one, so
/me/photos/96x96/$valuereturns 404. That’s expected; Persona falls back to initials. - A field shows a dash: Graph returns
nullfor profile fields nobody filled in, like my officeLocation. Handle empty values instead of printing “null”. - Empty email: anonymous sharing-link visitors have no email. Check
isAnonymousGuestUserbefore using it.
Want the finished project instead of typing it? It’s with our other ready-made solutions on the Power Platform and SPFx solutions page.
A few more SPFx guides that build on this one:
Frequently Asked Questions
How do I get the current user name in SPFx without an API call?
Read this.context.pageContext.user.displayName in the web part. SharePoint fills pageContext with the page, so it needs no request, no library and no permission. email and loginName are on the same object.
Does SPHttpClient use the current user’s credentials?
Yes. SPHttpClient includes the signed-in user’s SharePoint authentication cookies, so _api/web/currentuser and every other REST call run with that user’s permissions. No admin approval is needed.
Which Graph permission do I need to get the current user’s details?
User.Read, the least privileged delegated permission for GET /me and the user’s own photo. Request it with webApiPermissionRequests, as the Microsoft Learn MSGraphClientV3 guide explains.
Where do I put webApiPermissionRequests?
In config/package-solution.json, inside the solution object, as an array of { resource, scope } entries. The request reaches admins when you upload the package, as in the Microsoft Learn deployment steps.
How do I get all users for an SPFx employee directory?
Call /users through MSGraphClientV3 with User.ReadBasic.All or User.Read.All, page through results with $top and @odata.nextLink, and have an admin approve the scope on the API access page.

Hey! I’m Bijay Kumar, founder of SPGuides.com and a Microsoft Business Applications MVP (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and training videos. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.