/**
* @module flitter-auth/model/Oauth2BearerToken
*/
const Model = require('flitter-orm/src/model/Model')
/**
* Flitter model spec for an Oauth2BearerToken which is compatible
* with the node-oauth2-server package and can be used as authentication
* for internal or external APIs.
* @extends module:flitter-orm/src/model/Model~Model
*/
class Oauth2BearerToken extends Model {
/**
* Defines the services required by this model.
* @returns {Array<string>}
*/
static get services() {
return [...super.services, 'models', 'auth']
}
/**
* Defines the schema for this model.
* @returns {object}
*/
static get schema() {
return {
accessToken: String,
clientID: String,
expires: Date,
userID: String,
}
}
/**
* Get an instance of the {module:flitter-auth/model/Oauth2Client~Oauth2Client} model with
* the corresponding client id and secret.
* @param {string} clientID - the client ID
* @param {string} clientSecret - the client secret
* @param {function} callback - passed boolean for error as the first param and the client or null for the second
*/
static getClient(clientID, clientSecret, callback) {
const Client = this.prototype.models.get('auth::Oauth2Client')
Client.findOne({clientID, clientSecret}).then(client => {
if ( !client ) callback(false, null)
else callback(false, client)
})
}
/**
* Determines if the client with the specified ID is allowed to use
* the specified grant type.
* @param {string} clientID - the client ID
* @param {string} grantType - the grant type
* @param {function} callback - passed boolean for error and boolean for whether the client can use the grant type
*/
static grantTypeAllowed(clientID, grantType, callback) {
const Client = this.prototype.models.get('auth::Oauth2Client')
Client.findOne({clientID}).then(client => {
if ( !client ) callback(false, false)
else callback(false, client.can(grantType))
})
}
/**
* Attempts to authenticate a user by username and password. If that
* succeeds, fetches the {module:flitter-auth/model/User~User} instance.
* @param {string} username - the username
* @param {string} password - the attempted password
* @param {function} callback - passed boolean for error, and null or instance of the User on success
*/
static getUser(username, password, callback) {
// defaults to the default auth provider
const provider = this.prototype.auth.get_provider()
provider.get_login_args({username, password}).then(args => {
provider.login(...args).then(result => {
if ( !result ) callback(false, null)
else callback(false, result)
})
})
}
/**
* Save a new instance of this access token with the given parameters.
* @param {string} accessToken - the access token
* @param {string} clientID - the associated client ID
* @param {Date} expires - the datetime when the token expires
* @param {module:flitter-auth/model/User~User} user - the associated User instance
* @param {function} callback - passed null on success, or an error
*/
static saveAccessToken(accessToken, clientID, expires, user, callback) {
const token = new this({
accessToken,
clientID,
expires,
userID: user.id,
})
token.save().then(() => callback(null)).catch((error) => callback(error))
}
/**
* Given the access token, retrieve the information about that token
* in the format supported by node-oauth2-server.
* @param {string} bearerToken - the bearer token
* @param {function} callback - passed boolean for error, and null or the result of this.serialize() on success
*/
static getAccessToken(bearerToken, callback) {
this.findOne({accessToken: bearerToken})
.then(token => {
if ( !token ) callback(false, null)
else callback(null, token.serialize())
})
}
/**
* Given a bearer token, generate an instance of {module:flitter-auth/model/Oauth2AuthorizationTicket~Oauth2AuthorizationTicket}
* @param {string} bearerCode - the bearer token
* @param {function} callback - passed boolean for error, and null or object of information about the token
*/
static getAuthCode(bearerCode, callback) {
const Code = this.prototype.models.get('auth::Oauth2AuthorizationTicket')
Code.findOne({token: bearerCode, redeemed: false}).then(token => {
if ( !token ) callback(false, null)
else {
token.redeemed = true
token.save().then(() => {
callback(false, {
clientId: token.client_id,
userId: token.user_id,
expires: token.expires,
})
})
}
})
}
/**
* Serializes this instance to the format understood by node-oauth2-server.
* @returns {object}
*/
serialize() {
return {
user: {
id: this.userID,
},
expires: this.expires,
}
}
}
module.exports = exports = Oauth2BearerToken