Skip to content

Instantly share code, notes, and snippets.

@lancegliser
Last active October 21, 2016 20:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lancegliser/6f699e16332cfefc3357 to your computer and use it in GitHub Desktop.
Save lancegliser/6f699e16332cfefc3357 to your computer and use it in GitHub Desktop.
Example OAuth consumer code for emailer.emfluence.com. This was extracted from a functioning angularjs 1.3 based site.
// Define route for consuming the returning token, and attach our interceptor
app.config([
'$routeProvider',
'$httpProvider',
'$controllerProvider',
'$compileProvider',
'$filterProvider',
'$locationProvider',
'$sceDelegateProvider',
'$provide',
function(
$routeProvider,
$httpProvider,
$controllerProvider,
$compileProvider,
$filterProvider,
$locationProvider,
$sceDelegateProvider,
$provide
) {
/* Routes */
$routeProvider
// General
.when('/', {
templateUrl : 'app/core/templates/front.html',
controller : 'frontCtrl'
})
.when('/browser-not-supported', {
templateUrl : 'app/core/templates/browser-not-supported.html',
controller : 'browserNotSupportedCtrl'
})
.when('/authentication/token', {
templateUrl : 'app/authentication/token/index.html',
controller : 'authenticationTokenCtrl',
})
.otherwise({
redirectTo: '/'
});
$httpProvider.interceptors.push('$authInterceptor');
}]);
/* Authentication interceptor */
app.factory('$authInterceptor', function($q, $storage, $location, $platform) {
return {
'request': function(config) {
// Ignore requests to sites other than the API
if(
!config.url.match( $platform.hostname )
&& !config.url.match( $platform.proxyHostname )
){
return config;
}
// If an accessToken is stored use it
if( !!$storage.data.accessToken ){
switch(config.method){
case 'POST':
if( typeof config.data == 'undefined' ){
config.data = {};
}
config.data.accessToken = $storage.data.accessToken;
break;
case 'GET':
if( typeof config.params == 'undefined' ){
config.params = {};
}
config.params.accessToken = $storage.data.accessToken;
break;
}
}
return config;
},
response: function (response) {
// Ignore requests to sites other than the API
if(
!response.config.url.match( $platform.hostname )
&& !response.config.url.match( $platform.proxyHostname )
){
return response;
}
// Ignore non-data based calls
if( !response.data.hasOwnProperty('error') && !response.data.hasOwnProperty('success') ){
return response;
}
// Check the status
if(
(
response.data.hasOwnProperty('success')
&& !response.data.success
)
|| response.data.code != 0
|| (
response.data.hasOwnProperty('error')
&& !!response.data.success.error
)
){
if( $storage.data.debug ){
console.debug(
'Response rejected with status code: ' + response.data.code
+ '. See https://apidocs.emailer.emfluence.com/v1/#error-codes'
);
console.debug('Response: ', response);
}
return $q.reject(response);
}
return response;
},
'responseError': function(rejection) {
if(
!rejection.config.url.match( $platform.hostname )
&& !rejection.config.url.match( $platform.proxyHostname )
){
return $q.reject(rejection);
}
var logout = false;
switch(rejection.status){
case 401:
if( rejection.statusText == 'Unauthorized : CSRF validation failed' ){
logout = true;
}
break;
case 403:
logout = true;
break;
case 503:
$location.path('/maintenance');
break;
}
if( logout ){
$storage.data.loginRedirect = location.hash.substring(2);
$storage.persist();
$location.path('/logout');
}
return $q.reject(rejection);
}
};
});
/* Api Service */
app.factory('$platform', function ($storage, $location, $window) { /* Routes */
$routeProvider
// General
.when('/', {
templateUrl : 'app/core/templates/front.html',
controller : 'frontCtrl'
})
.when('/browser-not-supported', {
templateUrl : 'app/core/templates/browser-not-supported.html',
controller : 'browserNotSupportedCtrl'
})
var platform = {
hostname: 'api.emailer.emfluence.com'
,protocol: 'https'
,apiVersion: 'v1'
,clientId: ''
,proxyPath: '/proxy'
// ,clientSecret: Yea, no. See proxy for details
,settings: {
timezone: 'America/Chicago'
,contacts: {
importLimit: 1000
}
}
,init: function(){
switch($storage.data.environment){
case 'local':
this.proxyHostname = 'local-platform.example.com';
this.proxyProtocol = 'https';
this.clientId = '';
break;
case 'dev':
this.proxyHostname = 'dev-platform.example.com';
this.proxyProtocol = 'https';
this.clientId = '';
break;
default:
this.proxyHostname = 'platform.example.com';
this.proxyProtocol = 'https';
}
}
,getUrl: function(endpoint){
switch(endpoint){
case 'login/oauth/accessToken':
return this.proxyProtocol + '://' + this.proxyHostname + this.proxyPath + '/' + this.apiVersion + '/' + endpoint;
break;
default:
return this.protocol + '://' + this.hostname + '/' + this.apiVersion + '/' + endpoint;
}
}
// See https://apidocs.emailer.emfluence.com/v1/endpoints/emails/buildEmailContent#variables
,tokens: {
}
,authentication: {
authorizePath: 'login/oauth/authorize'
,tokenPath: 'login/oauth/accessToken'
,start: function(){
// Craft the login url
var url =
'https://emailer.emfluence.com/' + this.authentication.authorizePath
+ '?clientID=' + this.clientId
+ '&redirectURI=' + $location.protocol() + '://' + $location.host() + '/authentication/token';
// center the popup window
var left = screen.width/2 - 200
,top = screen.height/2 - 250;
// Fire
$window.open(url, '', "top=" + top + ",left=" + left + ",width=400,height=500");
}
,getExchangeUrl: function(){
return this.proxyProtocol + '://' + this.proxyHostname + this.proxyPath + '/' + this.authentication.tokenPath
}
}
,fields: {
firstName: {
label: 'First Name'
,keywords: ['first']
,validate: function(text){
return typeof text == 'string' && text.length > 0;
}
}
,lastName: {
label: 'Last Name'
,keywords: ['last']
,validate: function(text){
return typeof text == 'string' && text.length > 0;
}
}
,email: {
label: 'Email'
,keywords: ['email', 'e-mail']
,validate: function(text){
var re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
return re.test(text);
}
}
,company: {
label: 'Company'
,keywords: ['company', 'organization']
,validate: function(text){
return typeof text == 'string';
}
}
,title: {
label: 'Title'
,keywords: ['title', 'position']
,validate: function(text){
return typeof text == 'string';
}
}
,originalSource: {
label: 'Original Source'
,keywords: ['source']
,validate: function(text){
return typeof text == 'string';
}
}
,phone: {
label: 'Phone'
,keywords: ['phone']
,validate: function(text){
return typeof text == 'string' || typeof text == 'number';;
}
}
,address1: {
label: 'Street'
,keywords: ['address1', 'address_1', 'street']
,validate: function(text){
return typeof text == 'string';
}
}
,address2: {
label: 'Additional'
,keywords: ['address2', 'address_2', 'additional', 'suite', 'apt', 'apartment']
,validate: function(text){
return typeof text == 'string';
}
}
,city: {
label: 'City'
,keywords: ['city']
,validate: function(text){
return typeof text == 'string';
}
}
,state: {
label: 'State/Province'
,keywords: ['state', 'province']
,validate: function(text){
return typeof text == 'string';
}
}
,zipCode: {
label: 'Postal Code'
,keywords: ['zip', 'postal']
,validate: function(text){
return typeof text == 'string' || typeof text == 'number';
}
}
,country: {
label: 'Country'
,keywords: ['country']
,validate: function(text){
// Forcing ISO2
return typeof text == 'string' && (text.length == 0 || text.length == 2);
}
}
}
,validate: {
contact: function(contact, errors){
var field, value;
var valid = true;
if( !contact.hasOwnProperty('email') ){
valid = false;
errors.email = true;
}
// Loop through the defined contact fields validating each
for( field in contact ){
value = contact[field];
switch( field ) {
default:
if( !this.fields[field].validate(value) ){
valid = false;
errors[field] = true;
}
}
}
// Ensure the postal code for the US matches the 5 or 5+4 format
if(
!!contact.country
&& !!contact.zipCode
){
switch(contact.country){
case 'US':
// Check for the 5+4 first
var re = /^\d{5}\+\d{4}$/;
if( !re.test(contact.zipCode) ){
re = /^\d{5}$/;
if( !re.test(contact.zipCode) ){
console.debug('Zip code invalid:', contact.zipCode);
valid = false;
errors['zipCode'] = true;
}
}
break;
}
}
return valid;
}
}
}
return platform;
});
<p style="text-align: center;" ng-show="dataLoading">Loading your user account.</p>
<div class="loading" ng-show="dataLoading"><i class="fa fa-spin fa-spinner"></i></div>
app.lazy.controller('authenticationTokenCtrl', function(
$scope
,$http
,$routeParams
,$platform
,$location
,$timeout
,$storage
,Page
){
Page.title = 'Token Exchange';
// Sample incoming: /authentication/token?code=C3543168-8E36-4E33-92BB-160DC11CD0BD
// Exchange the code
if( !!$routeParams.error ){
$scope.setError($routeParams.error);
return;
}
if( !$routeParams.code ){
$scope.setError('No code was given to exchange for an access token.');
return;
}
var url = $platform.authentication.getExchangeUrl.bind($platform)();
var data = {
'clientID': $platform.clientId
,'code': $routeParams.code
// clientSecret will be added by the proxy
};
$scope.dataLoading = true;
$http.post(url, data)
.error(function(data, status){
if( $storage.data.debug ) {
console.debug('Post failure: ', data.error);
}
$scope.dataLoading = false;
$scope.setError(data.error);
})
.success(function(data){
if( $storage.data.debug ) {
console.debug('Post success updating $storage with:', data);
}
$storage.data.accessToken = data.accessToken;
$storage.persist();
// Retrieve user details
$http.get( $platform.getUrl('users/self') )
.error(function(response, status){
$scope.setError('An error occurred retrieving your user information.');
})
.success(function(response){
if( $storage.data.debug ) {
console.debug('User lookup success');
console.debug(response);
}
$storage.data.user = response.data;
$storage.persist();
$scope.setUser($storage.data.user);
$scope.dataLoading = false;
$scope.reload();
});
});
$scope.reload = function(){
if( window.opener != null ){
window.opener.location = '/';
window.close();
} else {
$location.path('/');
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment