Just to show the results of this exercise, this is our app:
Calling the service without being logged in and without cookies set, CAP is going to present a 401 on the service.
After logging in, cookies are present and CAP will let you through
http://localhost:4004/auth/github/callback
. Just remember to have a development version and a production version, or to switch URL's.npm install --save passport passport-github2 cookie-session
.env
file. Don't forget to add it to your .gitignore
therefore, your secrets are kept away from your Git repositories. In our example, we have the following:GITHUB_CLIENT_ID=xxx
GITHUB_CLIENT_SECRET=xxx
GITHUB_CALLBACK_URL=http://localhost:4004/auth/github/callback
const cds = require("@sap/cds");
const implementation = require('./serverImplementation');
cds.on("bootstrap", async (app) => await implementation(app));
module.exports = cds.server;
/* eslint-disable no-unused-vars */
const passport = require('passport');
const cookieSession = require('cookie-session')
require('../auth/passport')
module.exports = async (app) => {
//cookie-session converts the current session to an encrypted cookie using the
//keys below
app.use(cookieSession({
name: 'github-auth-session',
keys: ['key1', 'key2']
}))
//initialise passport and set it up to use sessions
app.use(passport.initialize());
app.use(passport.session());
/**
* Added for the purpose of oAuth example
*/
app.get('/auth/error', (_req, res) => res.send('Unknown Error'))
app.get('/auth/logout', (req, res) => {
req.session = null;
req.logout();
res.redirect('/');
})
app.get('/auth/my-user', (req, res) => {
res.json(req?.user?._json)
})
app.get('/auth/github', passport.authenticate('github', { scope: ['user:email'] }));
app.get('/auth/github/callback', passport.authenticate('github', { failureRedirect: '/auth/error' }),
function (_req, res) {
res.redirect('/');
});
}
auth/error
, this will get called when an error occursauth/logout
, this is the route that resets the session and removes the cookieauth/my-user
is the route that returns the current user as it is stored on the sessionauth/github
is the authenticating method, This will hand over to passport and tell passport to present the Github login screen and check the Github access token, if one is present. Passport in this case does all the heavy lifting, initiating the redirect to Github and asks for your username and password.auth/github/callback
is the method that's configured on the Github oAuth client, these have to match. If the callback on the oAuth client is not identical to the method on your CAP server, the redirections are not completed and your app will fail. After the user authenticates with Github, Passport takes over to turn the response from Github into a user session for the Express application to use.const passport = require('passport');
const GitHubStrategy = require('passport-github2').Strategy;
const { GITHUB_CALLBACK_URL, GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET } = process.env;
//methods to indicate how to serialise and deserialise the user object.
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (user, done) {
done(null, user);
});
//adding the Github strategy
passport.use(new GitHubStrategy({
clientID: GITHUB_CLIENT_ID,
clientSecret: GITHUB_CLIENT_SECRET,
callbackURL: GITHUB_CALLBACK_URL
},
function (accessToken, refreshToken, profile, done) {
return done(null, profile);
}
));
Users
table already, for instance, so that we can create a profile that is not just the GitHub profile..cdsrc.json
:{
"requires": {
"auth": {
"impl": "./auth/handler.js"
}
}
}
const cds = require("@sap/cds");
module.exports = (req, res, next) => {
if (req?.user) {
req.user = new cds.User(req.user)
next()
} else {
res.status(401).send();
}
}
user
object on the request, fetched and deserialised by Passport into a CDS.User
object. CAP uses this user to call its own methods, such as role check:req.user.is('admin')
user
object is not of type cds.User
the app will probably crash, since methods like the above are used internally./auth/github
and Passport will take over the redirections to our oAuth client, any button or link is fine. To log out, simply add a link to /auth/logout
to remove the cookie and the session.You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
6 | |
5 | |
4 | |
4 | |
3 | |
3 | |
3 | |
3 | |
3 | |
2 |