Lab - Simple OIDC Client
Context After seeing how OIDC client works using Passport.js (see lab), try again without.
Preparation
Create a folder and initialize a Node.js project
$ mkdir oidcapp
$ cd oidcapp
$ yarn init -y
$ yarn add express express-session openid-client
Add the Code
Add simple.js
in the top folder:
const express = require('express');
const session = require('express-session');
const { Issuer, generators } = require('openid-client');
const app = express();
app.use(session({ secret: 'secret', resave: false, saveUninitialized: true }));
var oidcClient;
Issuer.discover('http://localhost:3000/oidc')
.then(issuer => {
oidcClient = new issuer.Client({
client_id: 'oidccli_id',
client_secret: 'oidccli_secret',
redirect_uris: ['http://localhost:8080/login/callback'],
post_logout_redirect_uris: ['http://localhost:8080/'],
response_types: ['code'],
});
});
app.get('/login', (req, res, next) => {
if (req.session.user) return res.redirect('/profile');
const code_verifier = generators.codeVerifier();
const code_challenge = generators.codeChallenge(code_verifier);
req.session.code_verifier = code_verifier;
const url = oidcClient.authorizationUrl({
scope: 'openid',
code_challenge,
code_challenge_method: 'S256',
});
res.redirect(url);
});
app.get('/login/callback', async (req, res, next) => {
const code_verifier = req.session.code_verifier;
const params = oidcClient.callbackParams(req);
const tokenSet = await oidcClient.callback(
'http://localhost:8080/login/callback', params, { code_verifier },
);
delete req.session.code_verifier;
const claims = tokenSet.claims();
console.log('validated ID Token claims %j', claims);
req.session.user = {
...claims,
name: claims.sub,
email: claims.sub + '@example.com',
id_token: tokenSet.id_token,
};
return res.redirect('/profile');
});
app.get('/', (req, res) => {
if (req.session.user) {
res.send(`Hi, ${req.session.user.name} (${req.session.user.email}),<br>
you can go to <a href="/profile">profile</a>, or<br>
<a href="/logout">logout locally</a>, or<br>
<a href="/logout?oidc=1">logout globally</a>`);
} else {
res.send('<a href="/login">Log in with OIDC Provider</a>')
}
});
app.get('/profile', (req, res) =>{
res.send(`<pre>${JSON.stringify(req.session.user, null, 2)}</pre><a href="/">home</a>`);
});
app.get('/logout', (req, res) =>{
if (!req.session.user) return res.redirect('/');
let { token_id } = req.session.user;
delete req.session.user;
if (!req.query.oidc) {
res.redirect('/');
} else {
const url = oidcClient.endSessionUrl({ token_id_hint: token_id });
res.redirect(url);
}
});
app.listen(8080, () => {
console.log('Server running at http://localhost:8080');
});
Launch the Client App
Launch the client with node simple.js
:
$ node simple.js
Server running at http://localhost:8080
Notes
- Refer to https://github.com/panva/node-openid-client for the quick start.