Skip to content

Commit e2c2bd5

Browse files
authored
Merge pull request #52 from microsoftgraph/msal
Tutorial refresh
2 parents 5c4891c + 8ff9961 commit e2c2bd5

25 files changed

Lines changed: 894 additions & 1219 deletions

demo/README.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ If you don't have a Microsoft account, there are a couple of options to get a fr
3232

3333
![A screenshot of the application ID of the new app registration](/tutorial/images/aad-application-id.png)
3434

35-
1. Select **Authentication** under **Manage**. Locate the **Implicit grant** section and enable **ID tokens**. Choose **Save**.
36-
37-
![A screenshot of the Implicit grant section](/tutorial/images/aad-implicit-grant.png)
38-
3935
1. Select **Certificates & secrets** under **Manage**. Select the **New client secret** button. Enter a value in **Description** and select one of the options for **Expires** and choose **Add**.
4036

4137
![A screenshot of the Add a client secret dialog](/tutorial/images/aad-new-client-secret.png)
@@ -49,7 +45,7 @@ If you don't have a Microsoft account, there are a couple of options to get a fr
4945

5046
## Configure the sample
5147

52-
1. Rename the `.env.example` file to `.env`.
48+
1. Rename the `example.env` file to `.env`.
5349
1. Edit the `.env` file and make the following changes.
5450
1. Replace `YOUR_APP_ID_HERE` with the **Application Id** you got from the App Registration Portal.
5551
1. Replace `YOUR_APP_PASSWORD_HERE` with the password you got from the App Registration Portal.

demo/graph-tutorial/.env.example

Lines changed: 0 additions & 8 deletions
This file was deleted.

demo/graph-tutorial/app.js

Lines changed: 33 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -6,99 +6,45 @@ var express = require('express');
66
var path = require('path');
77
var cookieParser = require('cookie-parser');
88
var logger = require('morgan');
9-
var session = require('express-session');
10-
var flash = require('connect-flash');
9+
const session = require('express-session');
10+
const flash = require('connect-flash');
11+
const msal = require('@azure/msal-node');
1112
require('dotenv').config();
1213

13-
var passport = require('passport');
14-
var OIDCStrategy = require('passport-azure-ad').OIDCStrategy;
14+
var indexRouter = require('./routes/index');
15+
var usersRouter = require('./routes/users');
16+
var authRouter = require('./routes/auth');
17+
var calendarRouter = require('./routes/calendar');
1518

16-
// Configure passport
19+
var app = express();
1720

21+
// <MsalInitSnippet>
1822
// In-memory storage of logged-in users
1923
// For demo purposes only, production apps should store
2024
// this in a reliable storage
21-
var users = {};
22-
23-
// Passport calls serializeUser and deserializeUser to
24-
// manage users
25-
passport.serializeUser(function(user, done) {
26-
// Use the OID property of the user as a key
27-
users[user.profile.oid] = user;
28-
done (null, user.profile.oid);
29-
});
30-
31-
passport.deserializeUser(function(id, done) {
32-
done(null, users[id]);
33-
});
25+
app.locals.users = {};
3426

35-
// <ConfigureOAuth2Snippet>
36-
// Configure simple-oauth2
37-
const oauth2 = require('simple-oauth2').create({
38-
client: {
39-
id: process.env.OAUTH_APP_ID,
40-
secret: process.env.OAUTH_APP_PASSWORD
41-
},
27+
// MSAL config
28+
const msalConfig = {
4229
auth: {
43-
tokenHost: process.env.OAUTH_AUTHORITY,
44-
authorizePath: process.env.OAUTH_AUTHORIZE_ENDPOINT,
45-
tokenPath: process.env.OAUTH_TOKEN_ENDPOINT
46-
}
47-
});
48-
// </ConfigureOAuth2Snippet>
49-
50-
// Callback function called once the sign-in is complete
51-
// and an access token has been obtained
52-
// <SignInCompleteSnippet>
53-
async function signInComplete(iss, sub, profile, accessToken, refreshToken, params, done) {
54-
if (!profile.oid) {
55-
return done(new Error("No OID found in user profile."));
56-
}
57-
58-
try{
59-
const user = await graph.getUserDetails(accessToken);
60-
61-
if (user) {
62-
// Add properties to profile
63-
profile['email'] = user.mail ? user.mail : user.userPrincipalName;
30+
clientId: process.env.OAUTH_APP_ID,
31+
authority: process.env.OAUTH_AUTHORITY,
32+
clientSecret: process.env.OAUTH_APP_SECRET
33+
},
34+
system: {
35+
loggerOptions: {
36+
loggerCallback(loglevel, message, containsPii) {
37+
console.log(message);
38+
},
39+
piiLoggingEnabled: false,
40+
logLevel: msal.LogLevel.Verbose,
6441
}
65-
} catch (err) {
66-
return done(err);
6742
}
43+
};
6844

69-
// Create a simple-oauth2 token from raw tokens
70-
let oauthToken = oauth2.accessToken.create(params);
71-
72-
// Save the profile and tokens in user storage
73-
users[profile.oid] = { profile, oauthToken };
74-
return done(null, users[profile.oid]);
75-
}
76-
// </SignInCompleteSnippet>
77-
78-
// Configure OIDC strategy
79-
passport.use(new OIDCStrategy(
80-
{
81-
identityMetadata: `${process.env.OAUTH_AUTHORITY}${process.env.OAUTH_ID_METADATA}`,
82-
clientID: process.env.OAUTH_APP_ID,
83-
responseType: 'code id_token',
84-
responseMode: 'form_post',
85-
redirectUrl: process.env.OAUTH_REDIRECT_URI,
86-
allowHttpForRedirectUrl: true,
87-
clientSecret: process.env.OAUTH_APP_PASSWORD,
88-
validateIssuer: false,
89-
passReqToCallback: false,
90-
scope: process.env.OAUTH_SCOPES.split(' ')
91-
},
92-
signInComplete
93-
));
94-
95-
var indexRouter = require('./routes/index');
96-
var usersRouter = require('./routes/users');
97-
var authRouter = require('./routes/auth');
98-
var calendarRouter = require('./routes/calendar');
99-
var graph = require('./graph');
100-
101-
var app = express();
45+
// Create msal application object
46+
app.locals.msalClient = new msal.ConfidentialClientApplication(msalConfig);
47+
// </MsalInitSnippet>
10248

10349
// <SessionSnippet>
10450
// Session middleware
@@ -127,6 +73,12 @@ app.use(function(req, res, next) {
12773
res.locals.error.push({message: 'An error occurred', debug: errs[i]});
12874
}
12975

76+
// Check for an authenticated user and load
77+
// into response locals
78+
if (req.session.userId) {
79+
res.locals.user = app.locals.users[req.session.userId];
80+
}
81+
13082
next();
13183
});
13284
// </SessionSnippet>
@@ -150,21 +102,6 @@ app.use(express.urlencoded({ extended: false }));
150102
app.use(cookieParser());
151103
app.use(express.static(path.join(__dirname, 'public')));
152104

153-
// Initialize passport
154-
app.use(passport.initialize());
155-
app.use(passport.session());
156-
157-
// <AddProfileSnippet>
158-
app.use(function(req, res, next) {
159-
// Set the authenticated user in the
160-
// template locals
161-
if (req.user) {
162-
res.locals.user = req.user.profile;
163-
}
164-
next();
165-
});
166-
// </AddProfileSnippet>
167-
168105
app.use('/', indexRouter);
169106
app.use('/auth', authRouter);
170107
app.use('/calendar', calendarRouter);

demo/graph-tutorial/example.env

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
OAUTH_APP_ID=YOUR_APP_ID_HERE
2+
OAUTH_APP_SECRET=YOUR_APP_SECRET_HERE
3+
OAUTH_REDIRECT_URI=http://localhost:3000/auth/callback
4+
OAUTH_SCOPES='user.read,calendars.readwrite,mailboxsettings.read'
5+
OAUTH_AUTHORITY=https://login.microsoftonline.com/common/

demo/graph-tutorial/graph.js

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,75 @@ module.exports = {
88
getUserDetails: async function(accessToken) {
99
const client = getAuthenticatedClient(accessToken);
1010

11-
const user = await client.api('/me').get();
11+
const user = await client
12+
.api('/me')
13+
.select('displayName,mail,mailboxSettings,userPrincipalName')
14+
.get();
1215
return user;
1316
},
1417

15-
// <GetEventsSnippet>
16-
getEvents: async function(accessToken) {
18+
// <GetCalendarViewSnippet>
19+
getCalendarView: async function(accessToken, start, end, timeZone) {
1720
const client = getAuthenticatedClient(accessToken);
1821

1922
const events = await client
20-
.api('/me/events')
23+
.api('/me/calendarview')
24+
// Add Prefer header to get back times in user's timezone
25+
.header("Prefer", `outlook.timezone="${timeZone}"`)
26+
// Add the begin and end of the calendar window
27+
.query({ startDateTime: start, endDateTime: end })
28+
// Get just the properties used by the app
2129
.select('subject,organizer,start,end')
22-
.orderby('createdDateTime DESC')
30+
// Order by start time
31+
.orderby('start/dateTime')
32+
// Get at most 50 results
33+
.top(50)
2334
.get();
2435

2536
return events;
26-
}
27-
// </GetEventsSnippet>
37+
},
38+
// </GetCalendarViewSnippet>
39+
40+
// <CreateEventSnippet>
41+
createEvent: async function(accessToken, formData, timeZone) {
42+
const client = getAuthenticatedClient(accessToken);
43+
44+
// Build a Graph event
45+
const newEvent = {
46+
subject: formData.subject,
47+
start: {
48+
dateTime: formData.start,
49+
timeZone: timeZone
50+
},
51+
end: {
52+
dateTime: formData.end,
53+
timeZone: timeZone
54+
},
55+
body: {
56+
contentType: 'text',
57+
content: formData.body
58+
}
59+
};
60+
61+
// Add attendees if present
62+
if (formData.attendees) {
63+
newEvent.attendees = [];
64+
formData.attendees.forEach(attendee => {
65+
newEvent.attendees.push({
66+
type: 'required',
67+
emailAddress: {
68+
address: attendee
69+
}
70+
});
71+
});
72+
}
73+
74+
// POST /me/events
75+
await client
76+
.api('/me/events')
77+
.post(newEvent);
78+
},
79+
// </CreateEventSnippet>
2880
};
2981

3082
function getAuthenticatedClient(accessToken) {
@@ -38,4 +90,4 @@ function getAuthenticatedClient(accessToken) {
3890
});
3991

4092
return client;
41-
}
93+
}

0 commit comments

Comments
 (0)