Skip to content

Instantly share code, notes, and snippets.

@leefsmp
Last active July 19, 2016 10:44
Show Gist options
  • Save leefsmp/645ead055cad9a1e9ddefb836fe9a9d2 to your computer and use it in GitHub Desktop.
Save leefsmp/645ead055cad9a1e9ddefb836fe9a9d2 to your computer and use it in GitHub Desktop.
Forge endpoint oauth implementation for node
///////////////////////////////////////////////////////////////////////
// Copyright (c) Autodesk, Inc. All rights reserved
// Written by Philippe Leefsma 2016 - ADN/Developer Technical Services
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
///////////////////////////////////////////////////////////////////////
import ServiceManager from '../services/SvcManager'
import { serverConfig as config } from 'c0nfig'
import { OAuth2 } from 'oauth'
import express from 'express'
module.exports = function() {
var router = express.Router()
/////////////////////////////////////////////////////////////////////////////
// Initialize OAuth library
//
/////////////////////////////////////////////////////////////////////////////
var oauth2 = new OAuth2(
config.forge.oauth.clientId,
config.forge.oauth.clientSecret,
config.forge.oauth.baseUri,
config.forge.oauth.authorizationUri,
config.forge.oauth.accessTokenUri,
null)
/////////////////////////////////////////////////////////////////////////////
// Wait for Forge Service to get initialized and set 2-legged token
//
/////////////////////////////////////////////////////////////////////////////
ServiceManager.on('ForgeSvc', async(forgeSvc) => {
var scope = config.forge.oauth.scope.join(' ')
var token = await forgeSvc.requestToken(scope)
forgeSvc.setToken('2legged', token)
})
/////////////////////////////////////////////////////////////////////////////
// login endpoint
//
/////////////////////////////////////////////////////////////////////////////
router.post('/login', function (req, res) {
var authURL = oauth2.getAuthorizeUrl({
redirect_uri: config.forge.oauth.redirectUri,
scope: config.forge.oauth.scope.join(' ')
})
res.json(authURL + '&response_type=code')
})
/////////////////////////////////////////////////////////////////////////////
// Reply looks as follow:
//
// access_token: "fk7dd21P4FAhJWl6MptumGkXIuei",
// refresh_token: "TSJpg3xSXxUEAtevo3lIPEmjQUxXbcqNT9AZHRKYM3",
// results: {
// token_type: "Bearer",
// expires_in: 86399,
// access_token: "fk7dd21P4FAhJWl6MptumGkXIuei"
// }
//
/////////////////////////////////////////////////////////////////////////////
router.get('/oauth/callback', (req, res) => {
var socketSvc = ServiceManager.getService(
'SocketSvc')
// filter out errors (access_denied, ...)
if (req.query && req.query.error) {
if (req.session.socketId) {
socketSvc.broadcast(
'callback', req.query.error,
req.session.socketId)
}
res.json(req.query.error)
return
}
if(!req.query || !req.query.code) {
res.status(401)
res.json('invalid request')
return
}
oauth2.getOAuthAccessToken(
req.query.code, {
grant_type: 'authorization_code',
redirect_uri: config.forge.oauth.redirectUri
},
function (err, access_token, refresh_token, results) {
try {
var forgeSvc = ServiceManager.getService(
'ForgeSvc')
var token = {
expires_in: results.expires_in,
refresh_token: refresh_token,
access_token: access_token,
scope: config.forge.oauth.scope
}
forgeSvc.setToken(req.sessionID, token)
// request a downgraded token to provide to client App
// read-only for viewing
forgeSvc.refreshToken(token, 'data:read').then(
(clientToken) => {
forgeSvc.setClientToken(
req.sessionID, clientToken)
if(req.session.socketId) {
socketSvc.broadcast(
'callback', 'success',
req.session.socketId)
}
res.end('success')
})
}
catch(ex){
res.status(500)
res.end(ex)
}
}
)
})
/////////////////////////////////////////////////////////////////////////////
// logout route
//
/////////////////////////////////////////////////////////////////////////////
router.post('/logout', (req, res) => {
var forgeSvc = ServiceManager.getService(
'ForgeSvc')
forgeSvc.deleteToken(req.sessionID)
res.json('success')
})
///////////////////////////////////////////////////////////////////////////
// 3-legged client token: exposes a 'data:read' only token to client App
//
///////////////////////////////////////////////////////////////////////////
router.get('/token/3legged', async (req, res) => {
try {
var forgeSvc = ServiceManager.getService(
'ForgeSvc')
var token = await forgeSvc.getClientToken(
req.sessionID)
res.json({
access_token: token.access_token,
expires_in: forgeSvc.getExpiry(token)
})
}
catch (error) {
res.status(error.statusCode || 404)
res.json(error)
}
})
///////////////////////////////////////////////////////////////////////////
// 2-legged client token: exposes a 'data:read' only token to client App
//
///////////////////////////////////////////////////////////////////////////
router.get('/token/2legged', async(req, res) => {
try {
var forgeSvc = ServiceManager.getService(
'ForgeSvc')
var token = await forgeSvc.requestToken(
'data:read')
res.json(token)
}
catch (error) {
res.status(error.statusCode || 404)
res.json(error)
}
})
return router
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment