Initial commit

This commit is contained in:
Evert Prants 2019-08-31 14:08:22 +03:00
commit 8e79fee52f
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
7 changed files with 289 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
npm-debug.log*

89
README.md Normal file
View File

@ -0,0 +1,89 @@
# passport-icynet
Passport strategy for authentication with [Icy Network](https://icynet.eu) through the OAuth 2.0 API.
## Usage
`npm install passport-icynet --save`
#### Configure Strategy
The Icy Network authentication strategy authenticates users via a Icy Network user account and OAuth 2.0 token(s). A Icy Network API client ID, secret and redirect URL must be supplied when using this strategy. The strategy also requires a `verify` callback, which receives the access token and an optional refresh token, as well as a `profile` which contains the authenticated Icy Network user's profile. The `verify` callback must also call `cb` providing a user to complete the authentication.
```javascript
var IcyNetworkStrategy = require('passport-icynet').Strategy;
var scopes = ['image', 'email'];
passport.use(new Icy NetworkStrategy({
clientID: 'id',
clientSecret: 'secret',
callbackURL: 'callbackURL',
scope: scopes
},
function(accessToken, refreshToken, profile, cb) {
User.findOrCreate({ icynetId: profile.id }, function(err, user) {
return cb(err, user);
});
}));
```
#### Authentication Requests
Use `passport.authenticate()`, and specify the `'icynet'` strategy to authenticate requests.
For example, as a route middleware in an Express app:
```javascript
app.get('/auth/icynet', passport.authenticate('icynet'));
app.get('/auth/icynet/callback', passport.authenticate('icynet', {
failureRedirect: '/'
}), function(req, res) {
res.redirect('/secretstuff') // Successful auth
});
```
#### Refresh Token Usage
In some use cases where the profile may be fetched more than once or you want to keep the user authenticated, refresh tokens may wish to be used. A package such as `passport-oauth2-refresh` can assist in doing this.
Example:
`npm install passport-oauth2-refresh --save`
```javascript
var IcyNetworkStrategy = require('passport-icynet').Strategy
, refresh = require('passport-oauth2-refresh');
var icynetStrat = new Icy NetworkStrategy({
clientID: 'id',
clientSecret: 'secret',
callbackURL: 'callbackURL'
},
function(accessToken, refreshToken, profile, cb) {
profile.refreshToken = refreshToken; // store this for later refreshes
User.findOrCreate({ icynetId: profile.id }, function(err, user) {
if (err)
return done(err);
return cb(err, user);
});
});
passport.use(icynetStrat);
refresh.use(icynetStrat);
```
... then if we require refreshing when fetching an update or something ...
```javascript
refresh.requestNewAccessToken('icynet', profile.refreshToken, function(err, accessToken, refreshToken) {
if (err)
throw; // boys, we have an error here.
profile.accessToken = accessToken; // store this new one for our new requests!
});
```
## Examples
An Express server example can be found in the `/example` directory. Be sure to `npm install` in that directory to get the dependencies.
## Credits
* Jared Hanson - used passport-github to understand passport more and kind of as a base.

17
example/package.json Normal file
View File

@ -0,0 +1,17 @@
{
"name": "passport-icynet-example",
"version": "0.1.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "Evert \"Diamond\" Prants <evert@lunasqu.ee>",
"license": "ISC",
"dependencies": {
"express": "^4.13.4",
"express-session": "^1.13.0",
"passport": "^0.3.2"
}
}

54
example/server.js Normal file
View File

@ -0,0 +1,54 @@
var express = require('express')
, session = require('express-session')
, passport = require('passport')
, Strategy = require('../lib').Strategy
, app = express();
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
var scopes = ['image', 'email'];
passport.use(new Strategy({
clientID: '',
clientSecret: '',
callbackURL: 'http://localhost:5000/callback',
scope: scopes
}, function(accessToken, refreshToken, profile, done) {
process.nextTick(function() {
return done(null, profile);
});
}));
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
app.get('/', passport.authenticate('icynet', { scope: scopes }), function(req, res) {});
app.get('/callback',
passport.authenticate('icynet', { failureRedirect: '/' }), function(req, res) { res.redirect('/info') } // auth success
);
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
app.get('/info', checkAuth, function(req, res) {
res.json(req.user);
});
function checkAuth(req, res, next) {
if (req.isAuthenticated()) return next();
res.send('not logged in :(');
}
app.listen(5000, function (err) {
if (err) return console.log(err)
console.log('Listening at http://localhost:5000/')
})

14
lib/index.js Normal file
View File

@ -0,0 +1,14 @@
/**
* Module dependencies.
*/
var Strategy = require('./strategy');
/**
* Expose `Strategy` directly from package.
*/
exports = module.exports = Strategy;
/**
* Export constructors.
*/
exports.Strategy = Strategy;

85
lib/strategy.js Normal file
View File

@ -0,0 +1,85 @@
/**
* Dependencies
*/
var OAuth2Strategy = require('passport-oauth2')
, InternalOAuthError = require('passport-oauth2').InternalOAuthError
, util = require('util');
/**
* `Strategy` constructor.
*
* The Icy Network authentication strategy authenticates requests by delegating
* to Icy Network via the OAuth2.0 protocol
*
* Applications must supply a `verify` callback which accepts an `accessToken`,
* `refreshToken` and service-specific `profile`, and then calls the `cb`
* callback supplying a `user`, which should be set to `false` if the
* credentials are not valid. If an exception occured, `err` should be set.
*
* Options:
* - `clientID` OAuth ID to icynet
* - `clientSecret` OAuth Secret to verify client to icynet
* - `callbackURL` URL that icynet will redirect to after auth
* - `scope` Array of permission scopes to request
* Check the official documentation for valid scopes to pass as an array.
*
* @constructor
* @param {object} options
* @param {function} verify
* @access public
*/
function Strategy(options, verify) {
options = options || {};
options.authorizationURL = options.authorizationURL || 'https://icynet.eu/oauth2/authorize';
options.tokenURL = options.tokenURL || 'https://icynet.eu/oauth2/token';
options.scopeSeparator = options.scopeSeparator || ' ';
OAuth2Strategy.call(this, options, verify);
this.name = 'icynet';
this._oauth2.useAuthorizationHeaderforGET(true);
}
/**
* Inherits from `OAuth2Strategy`
*/
util.inherits(Strategy, OAuth2Strategy);
/**
* Retrieve user profile from Icy Network.
*
* This function constructs a normalized profile.
* Along with the properties returned from /oauth2/user, properties returned include:
* - `email` Email address if you requested this scope
* - `image` Profile picture if you requested this scope
* - `privilege` Icy Network privilege level if you requested this scope
* - `accessToken` The access token used to fetch the (may be useful for refresh)
*
* @param {string} accessToken
* @param {function} done
* @access protected
*/
Strategy.prototype.userProfile = function(accessToken, done) {
var self = this;
this._oauth2.get('https://icynet.eu/oauth2/user', accessToken, function(err, body, res) {
if (err) {
return done(new InternalOAuthError('Failed to fetch the user profile.', err))
}
try {
var parsedData = JSON.parse(body);
} catch (e) {
return done(new Error('Failed to parse the user profile.'));
}
var profile = parsedData; // has the basic user stuff
profile.provider = 'icynet';
profile.accessToken = accessToken;
done(null, profile)
});
};
/**
* Expose `Strategy`.
*/
module.exports = Strategy;

28
package.json Normal file
View File

@ -0,0 +1,28 @@
{
"name": "passport-icynet",
"version": "0.0.1",
"description": "Passport strategy for authentication with Icy Network (icynet.eu)",
"main": "lib/index.js",
"repository": {
"type": "git",
"url": "git+https://gitlab.icynet.eu/IcyNetwork/passport-icynet.git"
},
"keywords": [
"passport",
"icynet",
"auth",
"authentication",
"authn",
"identity",
"oauth2"
],
"author": "Evert \"Diamond\" Prants <evert@lunasqu.ee>",
"license": "MIT",
"bugs": {
"url": "https://gitlab.icynet.eu/IcyNetwork/passport-icynet/issues"
},
"homepage": "https://gitlab.icynet.eu/IcyNetwork/passport-icynet#readme",
"dependencies": {
"passport-oauth2": "^1.2.0"
}
}