Socket
Socket
Sign inDemoInstall

caccl-authorizer

Package Overview
Dependencies
Maintainers
1
Versions
113
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.4 to 1.0.5

cypress.json

86

index.js

@@ -5,4 +5,6 @@ const fs = require('fs');

const API = require('caccl-api');
const CACCLError = require('caccl-error');
const sendRequest = require('caccl-send-request');
const parseLaunch = require('caccl-lti/parseLaunch');

@@ -68,4 +70,7 @@ const MemoryTokenStore = require('./MemoryTokenStore.js');

* both functions return promises
* @param {function} [onManualLogin] - a function to call with params (req, res)
* @param {function} [onLogin] - a function to call with params (req, res)
* after req.logInManually is called and finishes manually logging in
* @param {boolean} [allowAuthorizationWithoutLaunch] - if true, allows user to
* be authorized even without a launch (when no LTI launch occurred and
* simulateLaunchOnAuthorize is false)
* @param {boolean} [simulateLaunchOnAuthorize] - if truthy, simulates an LTI

@@ -100,3 +105,7 @@ * launch upon successful authorization (if the user hasn't already launched

// Initialize autoRefreshRoutes
const autoRefreshRoutes = config.autoRefreshRoutes || ['*'];
const autoRefreshRoutes = (
config.autoRefreshRoutes === null
? []
: config.autoRefreshRoutes || ['*']
);

@@ -152,3 +161,4 @@ // Initialize the default authorized redirect path

const accessToken = body.access_token;
const accessTokenExpiry = new Date().getTime() + 3540000;
const expiresIn = (body.expires_in * 1000);
const accessTokenExpiry = new Date().getTime() + expiresIn;
// Save credentials

@@ -175,4 +185,4 @@ return req.logInManually(accessToken, refreshToken, accessTokenExpiry);

// Send callback
if (config.onManualLogin) {
config.onManualLogin(req, res);
if (config.onLogin) {
config.onLogin(req, res);
}

@@ -208,3 +218,2 @@

|| !req.session.accessToken
|| !req.session.accessTokenExpiry
|| !req.session.refreshToken

@@ -217,3 +226,6 @@ ) {

// Check if token has expired
if (new Date().getTime() < req.session.accessTokenExpiry) {
if (
req.session.accessTokenExpiry
&& new Date().getTime() < req.session.accessTokenExpiry
) {
// Not expired yet. Don't need to refresh

@@ -243,2 +255,7 @@ return next();

config.app.get(launchPath, (req, res, next) => {
if (!req.session) {
// No session! Cannot authorize without session
return res.status(403).send('Internal error: cannot authorize without express-session initialized on the app.');
}
// Skip if not step 1

@@ -256,5 +273,14 @@ if (req.query.code && req.query.state) {

// LTI launches
if (!req.session.launchInfo && !config.simulateLaunchOnAuthorize) {
const launchOccurred = (
req.session
&& req.session.launchInfo
&& Object.keys(req.session.launchInfo).length > 0
);
if (
!launchOccurred
&& !config.simulateLaunchOnAuthorize
&& !config.allowAuthorizationWithoutLaunch
) {
// Cannot authorize
return res.status(403).send(`Please launch ${appName} again via Canvas.`);
return res.status(403).send(`Please launch ${appName} via Canvas.`);
}

@@ -345,2 +371,3 @@

let launchUserId;
let accessToken;
sendRequest({

@@ -362,4 +389,10 @@ host: canvasHost,

// Detect invalid client_secret error
if (body.error && body.error === 'invalid_client') {
res.redirect(nextPath + '?success=false&reason=invalid_client');
throw new Error('break');
}
// Extract token
const accessToken = body.access_token;
accessToken = body.access_token;
const refreshToken = body.refresh_token;

@@ -439,4 +472,11 @@ const expiresInMs = (body.expires_in * 0.99 * 1000);

if (config.simulateLaunchOnAuthorize && !req.session.launchInfo) {
// Get API
const api = new API({
accessToken,
canvasHost,
cacheType: null,
});
// Pull list of courses, ask user to choose a course
return req.api.user.self.listCourses({ includeTerm: true })
return api.user.self.listCourses({ includeTerm: true })
.then((courses) => {

@@ -455,3 +495,6 @@ return renderCourseChooser({

})
.catch(() => {
.catch((err) => {
if (err.message === 'break') {
return;
}
return res.redirect(nextPath + '?success=false&reason=error');

@@ -463,3 +506,7 @@ });

config.app.get(launchPath, (req, res, next) => {
if (!req.query.course || !req.api) {
if (
!req.query.course
|| !req.session
|| !req.session.accessToken
) {
return next();

@@ -471,2 +518,9 @@ }

// Create API
const api = new API({
canvasHost,
accessToken: req.session.accessToken,
cacheType: null,
});
// Simulate the launch

@@ -476,4 +530,4 @@

Promise.all([
req.api.course.get({ courseId }),
req.api.user.self.getProfile(),
api.course.get({ courseId }),
api.user.self.getProfile(),
])

@@ -490,3 +544,3 @@ .then(([course, profile]) => {

// Parse and save the simulated launch
return req._parseLaunch(simulatedLTILaunchBody);
return parseLaunch(simulatedLTILaunchBody, req);
})

@@ -493,0 +547,0 @@ .then(() => {

26

package.json
{
"name": "caccl-authorizer",
"version": "1.0.4",
"version": "1.0.5",
"description": "Acquires Canvas tokens through via OAuth, stores refresh tokens, and refreshes access tokens when they expire.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "node test"
},

@@ -31,20 +31,28 @@ "repository": {

"body-parser": "^1.18.3",
"eslint": "^5.8.0",
"caccl": "^1.0.41",
"caccl-canvas-partial-simulator": "^1.0.9",
"dce-selenium": "^1.0.12",
"eslint": "^5.13.0",
"eslint-config-airbnb": "^17.1.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-jsx-a11y": "^6.1.2",
"eslint-plugin-react": "^7.11.1",
"eslint-plugin-cypress": "^2.2.0",
"eslint-plugin-import": "^2.16.0",
"eslint-plugin-jsx-a11y": "^6.2.0",
"eslint-plugin-react": "^7.12.4",
"express": "^4.16.4",
"express-session": "^1.15.6",
"fs": "0.0.1-security",
"https": "^1.0.0"
"https": "^1.0.0",
"ims-lti": "^3.0.2",
"mocha": "^5.2.0"
},
"dependencies": {
"axios": "^0.18.0",
"caccl-api": "^1.0.9",
"caccl-error": "^1.0.0",
"caccl-send-request": "^1.0.7",
"caccl-lti": "^1.0.5",
"caccl-send-request": "^1.0.9",
"ejs": "^2.6.1",
"qs": "^6.5.2",
"qs": "^6.6.0",
"randomstring": "^1.1.5"
}
}

@@ -1,2 +0,85 @@

# caccl-token-manager
Acquires Canvas tokens through via OAuth, stores refresh tokens, and refreshes access tokens when they expire.
# caccl-authorizer
Handles app authorization, redirecting users to the "Authorize this App" page, acquiring access tokens, and refreshing access tokens when they expire.
Your LTI app accepts launches at your `launchPath` via POST. `caccl-authorizer` uses that same path to kick off the Canvas authorization process: direct users to your `launchPath` via GET and they'll be authorized and then redirected to the `defaultAuthorizedRedirect` path.
## Part of the CACCL library
**C**anvas
**A**pp
**C**omplete
**C**onnection
**L**ibrary
## Quickstart
After creating your express app but before adding routes, initialize `caccl-authorizer` to add routes and middleware to make authorization possible.
```js
const initAuthorization = require('caccl-authorizer');
// TODO: create express app
initAuthorization({
app: /* express app with express-session enabled*/,
developerCredentials: {
client_id: /* developer client id */,
client_secret: /* developer client secret */,
},
canvasHost: /* your canvas host name */,
});
// TODO: add routes to express app
```
To authorize a user, redirect them to the `launchPath` via GET. `caccl-authorizer` will handle the entire authorization process then redirect them to the `defaultAuthorizedRedirect` path. After authorization, the user's access token will appear in their session: `req.session.accessToken`.
**Important:** you must initialize `caccl-authorizer` before adding refreshed routes (see `autoRefreshRoutes` below).
## Configuration Options
When initializing `caccl-authorizer`, you can pass in many different configuration options to customize CACCL's behavior or turn on/off certain functionality.
**Note:** configuration options are _optional_ unless otherwise stated
### Main Configuration Options
Important configuration options you probably should include.
Config Option | Type | Description | Default/Required
:--- | :--- | :--- | :---
app | express app | the server express app with express-session enabled | **required**
developerCredentials | object | canvas app developer credentials in the form: `{ client_id, client_secret }` | **required**
canvasHost | string | canvas host to use for oauth exchange | canvas.instructure.com
allowAuthorizationWithoutLaunch | boolean | if true, allows user to be authorized even without a launch (when no LTI launch occurred and simulateLaunchOnAuthorize is false) | false
### App Information
Optional information about your app.
Config Option | Type | Description | Default
:--- | :--- | :--- | :---
appName | string | the name of the app for use in simulated launches and in errors | "this app"
launchPath | string | redirect users to this path via GET to kick off the authorization process | "/launch"
### Authorization Configuration
Options that change how authorization functions. By default, when authorization is complete, the user will be redirected to `/`, and when the access token expires (after 1hr), it will automatically be refreshed when the user visits any route (`*`). The refresh tokens are stored in a `memory token store`. All of these features can be customized via the config options below.
Config Option | Type | Description | Default
:--- | :--- | :--- | :---
defaultAuthorizedRedirect | string | the default route to visit after authorization is complete (you can override this for a specific authorization call by including `query.next`. example: `/launch?next=/profile`) | "/"
autoRefreshRoutes | string[] | list of routes to automatically refresh the access token for (if the access token has expired), these routes must be added _after_ `caccl-authorizer` has been initialized | `["*"]`
tokenStore | [TokenStore](https://github.com/harvard-edtech/caccl-authorizer/blob/master/docs/TokenStore.md) | null to turn off storage of refresh tokens, exclude to use memory token store, or include a custom token store (see [these docs](https://github.com/harvard-edtech/caccl-authorizer/blob/master/docs/TokenStore.md)) | memory store
**Tip:** we recommend setting `autoRefreshRoutes` to all the paths where you will need access to the Canvas API. Then, the accessToken will never have expired when the user visits one of those paths.
### Simulated Launch Options
Enabling this feature allows users to visit the `launchPath` (GET), go through the authorization process, and then `caccl-authorizer` simulates an LTI launch. This essentially makes it possible for users to launch your app without visiting Canvas, simply by visiting the `launchPath`.
To enable this feature,
Config Option | Type | Description | Default
:--- | :--- | :--- | :---
simulateLaunchOnAuthorize | boolean | if true, simulates an LTI launch upon successful authorization (if the user hasn't already launched via LTI) | false
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc