Skip to content

Commit

Permalink
feat: added device code manager
Browse files Browse the repository at this point in the history
  • Loading branch information
valmoz authored Jun 17, 2024
1 parent c6470b8 commit 5fea252
Show file tree
Hide file tree
Showing 7 changed files with 333 additions and 126 deletions.
24 changes: 19 additions & 5 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,9 +269,11 @@ import Conjunction from './filter/Conjunction'
import Disjunction from './filter/Disjunction'
import Operator from './filter/Operator'

import OAuth2AuthorizationCodeManager from './oauth2/OAuth2'
import OAuth2AuthorizationCodeTokenResponse from './oauth2/OAuth2AuthorizationCodeTokenResponse'
import OAuth2AuthorizationCodeManager from './oauth2/OAuth2AuthorizationCode'
import OAuth2AuthorizationCodeParams from './oauth2/OAuth2AuthorizationCodeParams'
import OAuth2DeviceCodeManager from './oauth2/OAuth2DeviceCode'
import OAuth2DeviceCodeResponse from './oauth2/OAuth2DeviceCodeResponse'
import OAuth2TokenResponse from './oauth2/OAuth2TokenResponse'
import Scope from './oauth2/Scope'

/**
Expand Down Expand Up @@ -349,17 +351,29 @@ export {
*/
OAuth2AuthorizationCodeManager,

/**
* The OAuth2DeviceCodeManager service constructor.
* @property {module:api/OAuth2DeviceCodeManager}
*/
OAuth2DeviceCodeManager,

/**
* The Scope service constructor.
* @property {module:api/Scope}
*/
Scope,

/**
* The OAuth2AuthorizationCodeTokenResponse service constructor.
* @property {module:api/OAuth2AuthorizationCodeTokenResponse}
* The OAuth2TokenResponse service constructor.
* @property {module:api/OAuth2TokenResponse}
*/
OAuth2TokenResponse,

/**
* The OAuth2DeviceCodeResponse service constructor.
* @property {module:api/OAuth2DeviceCodeResponse}
*/
OAuth2AuthorizationCodeTokenResponse,
OAuth2DeviceCodeResponse,

/**
* The OAuth2AuthorizationCodeParams service constructor.
Expand Down
108 changes: 13 additions & 95 deletions src/oauth2/OAuth2.js
Original file line number Diff line number Diff line change
@@ -1,129 +1,47 @@
import superagent from 'superagent'
import OAuth2AuthorizationCodeParams from './OAuth2AuthorizationCodeParams'
import OAuth2AuthorizationCodeTokenResponse from './OAuth2AuthorizationCodeTokenResponse'
import OAuth2TokenResponse from './OAuth2TokenResponse'

/**
* The OAuth2AuthorizationCodeManager oauth module.
* @module oauth2/OAuth2AuthorizationCodeManager
* The OAuth2Manager oauth module.
* @module oauth2/OAuth2Manager
*/
export default class OAuth2AuthorizationCodeManager {
export default class OAuth2Manager {
/**
* The client id.
* @member {String} clientId
*/
clientId

/**
* The client secret.
* @member {String} clientSecret
*/
clientSecret

/**
* The redirect uri.
* @member {String} redirectUri
*/
redirectUri

/**
* The base uri.
* @member {String} baseUri
*/
baseUri = 'https://api-v2.fattureincloud.it'

/**
* Constructs a new <code>OAuth2AuthorizationCodeManager</code>.
* Constructs a new <code>OAuth2Manager</code>.
* @param {String} clientId The client id.
* @param {String} clientSecret The client secret.
* @param {String} redirectUri The redirect uri.
* @param {String} baseUri The base uri.
*/
constructor (clientId, clientSecret, redirectUri, baseUri = 'https://api-v2.fattureincloud.it') {
constructor (clientId, baseUri = 'https://api-v2.fattureincloud.it') {
this.clientId = clientId
this.clientSecret = clientSecret
this.redirectUri = redirectUri
this.baseUri = baseUri
}

/**
* Get the authorization url.
* @param {Array.<oauth2/Scope>} scopes The scopes.
* @return {String} The query.
*/
getAuthorizationUrl (scopes, state) {
const authorizationUri = `${this.baseUri}/oauth/authorize`
const scopeStr = OAuth2AuthorizationCodeManager.getScopeString(scopes)

const params = {
response_type: 'code',
client_id: this.clientId,
redirect_uri: this.redirectUri,
scope: scopeStr,
state
}
const query = new URLSearchParams(params).toString()

return `${authorizationUri}?${query}`
}

/**
* Extracts parameters from a URL and returns an OAuth2AuthorizationCodeParams object.
* @param {string} url - The URL containing the parameters.
* @returns {OAuth2AuthorizationCodeParams} - The OAuth2AuthorizationCodeParams object containing the extracted parameters.
*/
getParamsFromUrl (url) {
const query = url.split('?')[1]
const params = new URLSearchParams(query)

return new OAuth2AuthorizationCodeParams(params.get('code'), params.get('state'))
}

/**
* Fetches the token using the provided authorization code.
* @param {string} code - The authorization code.
* @returns {Promise} - A promise that resolves with the token response.
*/
fetchToken (code) {
const tokenUri = `${this.baseUri}/oauth/token`

const data = {
grant_type: 'authorization_code',
client_id: this.clientId,
client_secret: this.clientSecret,
redirect_uri: this.redirectUri,
code
}

return this.tokenRequest(tokenUri, data)
}

/**
* Refreshes the access token using the provided refresh token.
* @param {string} refreshToken - The refresh token to use for token refresh.
* @returns {Promise} - A promise that resolves with the refreshed access token.
*/
refreshToken (refreshToken) {
const tokenUri = `${this.baseUri}/oauth/token`

const data = {
grant_type: 'refresh_token',
client_id: this.clientId,
client_secret: this.clientSecret,
refresh_token: refreshToken
}

return this.tokenRequest(tokenUri, data)
}

tokenRequest (uri, data) {
tokenRequest (uri, data, mapFunc) {
return superagent.post(uri).send(data)
.then(({ body }) => {
return new OAuth2AuthorizationCodeTokenResponse(body.token_type, body.access_token, body.refresh_token, body.expires_in)
return mapFunc(body)
})
.catch(e => {
throw new Error(e.response.text)
})
}

mapToTokenResponse (body) {
return new OAuth2TokenResponse(body.token_type, body.access_token, body.refresh_token, body.expires_in)
}

static getScopeString (scopes) {
return scopes.map(scope => scope.toString()).join(' ')
}
Expand Down
103 changes: 103 additions & 0 deletions src/oauth2/OAuth2AuthorizationCode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import OAuth2AuthorizationCodeParams from './OAuth2AuthorizationCodeParams'
import OAuth2Manager from './OAuth2'

/**
* The OAuth2AuthorizationCodeManager oauth module.
* @module oauth2/OAuth2AuthorizationCodeManager
*/
export default class OAuth2AuthorizationCodeManager extends OAuth2Manager {
/**
* The client secret.
* @member {String} clientSecret
*/
clientSecret

/**
* The redirect uri.
* @member {String} redirectUri
*/
redirectUri

/**
* Constructs a new <code>OAuth2AuthorizationCodeManager</code>.
* @param {String} clientId The client id.
* @param {String} clientSecret The client secret.
* @param {String} redirectUri The redirect uri.
* @param {String} baseUri The base uri.
*/
constructor (clientId, clientSecret, redirectUri, baseUri = 'https://api-v2.fattureincloud.it') {
super(clientId, baseUri)
this.clientSecret = clientSecret
this.redirectUri = redirectUri
}

/**
* Get the authorization url.
* @param {Array.<oauth2/Scope>} scopes The scopes.
* @return {String} The query.
*/
getAuthorizationUrl (scopes, state) {
const authorizationUri = `${this.baseUri}/oauth/authorize`
const scopeStr = OAuth2AuthorizationCodeManager.getScopeString(scopes)

const params = {
response_type: 'code',
client_id: this.clientId,
redirect_uri: this.redirectUri,
scope: scopeStr,
state
}
const query = new URLSearchParams(params).toString()

return `${authorizationUri}?${query}`
}

/**
* Extracts parameters from a URL and returns an OAuth2AuthorizationCodeParams object.
* @param {string} url - The URL containing the parameters.
* @returns {OAuth2AuthorizationCodeParams} - The OAuth2AuthorizationCodeParams object containing the extracted parameters.
*/
getParamsFromUrl (url) {
const query = url.split('?')[1]
const params = new URLSearchParams(query)

return new OAuth2AuthorizationCodeParams(params.get('code'), params.get('state'))
}

/**
* Fetches the token using the provided authorization code.
* @param {string} code - The authorization code.
* @returns {Promise} - A promise that resolves with the token response.
*/
fetchToken (code) {
const tokenUri = `${this.baseUri}/oauth/token`

const data = {
grant_type: 'authorization_code',
client_id: this.clientId,
client_secret: this.clientSecret,
redirect_uri: this.redirectUri,
code
}

return this.tokenRequest(tokenUri, data, this.mapToTokenResponse)
}

/**
* Refreshes the access token using the provided refresh token.
* @param {string} refreshToken - The refresh token to use for token refresh.
* @returns {Promise} - A promise that resolves with the refreshed access token.
*/
refreshToken (refreshToken) {
const tokenUri = `${this.baseUri}/oauth/token`

const data = {
grant_type: 'refresh_token',
client_id: this.clientId,
client_secret: this.clientSecret,
refresh_token: refreshToken
}

return this.tokenRequest(tokenUri, data, this.mapToTokenResponse)
}
}
72 changes: 72 additions & 0 deletions src/oauth2/OAuth2DeviceCode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import OAuth2DeviceCodeResponse from './OAuth2DeviceCodeResponse'
import OAuth2Manager from './OAuth2'

/**
* The OAuth2DeviceCodeManager oauth module.
* @module oauth2/OAuth2DeviceCodeManager
*/
export default class OAuth2DeviceCodeManager extends OAuth2Manager {
/**
* Constructs a new <code>OAuth2DeviceCodeManager</code>.
* @param {String} clientId The client id.
* @param {String} baseUri The base uri.
*/
constructor (clientId, baseUri = 'https://api-v2.fattureincloud.it') {
super(clientId, baseUri)
}

/**
* Gets the device code to init the flow.
* @param {Array.<oauth2/Scope>} scopes The scopes.
* @returns {Promise} - A promise that resolves with the device code response.
*/
getDeviceCode (scopes) {
const tokenUri = `${this.baseUri}/oauth/device`
const scopeStr = OAuth2DeviceCodeManager.getScopeString(scopes)

const data = {
client_id: this.clientId,
scope: scopeStr
}

return this.tokenRequest(tokenUri, data, this.mapToDeviceCodeResponse)
}

/**
* Fetches the token using the provided device code.
* @param {string} code - The device code.
* @returns {Promise} - A promise that resolves with the token response.
*/
fetchToken (code) {
const tokenUri = `${this.baseUri}/oauth/token`

const data = {
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
client_id: this.clientId,
device_code: code
}

return this.tokenRequest(tokenUri, data, this.mapToTokenResponse)
}

/**
* Refreshes the access token using the provided refresh token.
* @param {string} refreshToken - The refresh token to use for token refresh.
* @returns {Promise} - A promise that resolves with the refreshed access token.
*/
refreshToken (refreshToken) {
const tokenUri = `${this.baseUri}/oauth/token`

const data = {
grant_type: 'refresh_token',
client_id: this.clientId,
refresh_token: refreshToken
}

return this.tokenRequest(tokenUri, data, this.mapToTokenResponse)
}

mapToDeviceCodeResponse (body) {
return new OAuth2DeviceCodeResponse(body.data.device_code, body.data.user_code, body.data.scope, body.data.verification_uri, body.data.interval, body.data.expires_in)
}
}
Loading

0 comments on commit 5fea252

Please sign in to comment.