diff --git a/auth-helper-dropbox.ts b/auth-helper-dropbox.ts
new file mode 100644
index 0000000..3f3f4b0
--- /dev/null
+++ b/auth-helper-dropbox.ts
@@ -0,0 +1,34 @@
+///
+
+import * as tnsOauth from './tns-oauth';
+import { AuthHelper } from './auth-helper';
+import * as TnsOAuth from './tns-oauth-interfaces';
+
+/**
+ Contains DropBox connection credentials
+*/
+export class AuthHelperDropBox extends AuthHelper implements TnsOAuth.ITnsAuthHelper {
+ //Constructs the the object with specified id, secret and scope
+ constructor(clientId: string, clientSecret: string, redirectUri: string, scope: Array) {
+ super();
+ var scopeStr = scope.join('%20');
+ this.credentials = {
+ authority: 'https://www.dropbox.com',
+ tokenEndpointBase: 'https://api.dropboxapi.com',
+ authorizeEndpoint: '/oauth2/authorize',
+ tokenEndpoint: '/oauth2/token',
+ clientId: clientId,
+ clientSecret: clientSecret,
+ redirectUri: redirectUri,
+ scope: scopeStr,
+ ignoredAuthParams: ['response_mode','nonce'],
+ ignoredTokenParams: ['response_mode','nonce','state'],
+ skipNextTokenNav: true
+ };
+ }
+ //Gets cookie domains for logging out
+ public logout(successPage?: string): Promise {
+ let cookieDomains = [".dropbox.com"];
+ return this._logout(successPage, cookieDomains);
+ }
+}
diff --git a/demo-angular/app/main.ts b/demo-angular/app/main.ts
index d553a07..131315a 100644
--- a/demo-angular/app/main.ts
+++ b/demo-angular/app/main.ts
@@ -24,6 +24,14 @@ var facebookInitOptions: tnsOAuthModule.ITnsOAuthOptionsFacebook = {
tnsOAuthModule.initFacebook(facebookInitOptions);
+// var dropboxInitOptions: tnsOAuthModule.ITnsOAuthOptionsDropBox = {
+// clientId: 'XXXXXXXXXX',
+// clientSecret: 'XXXXXXXXXX',
+// redirectUri: 'http://localhost',
+// scope: [],
+// };
+
+// tnsOAuthModule.initDropBox(dropboxInitOptions);
// let uaaInitOptions: tnsOAuthModule.ITnsOAuthOptionsUaa = {
diff --git a/index.d.ts b/index.d.ts
index a7e9935..b36d80a 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -9,6 +9,7 @@ export declare function initGoogle(options: TnsOAuth.ITnsOAuthOptionsGoogle): Pr
export declare function initUaa(options: TnsOAuth.ITnsOAuthOptionsUaa): Promise;
export declare function initLinkedIn(options: TnsOAuth.ITnsOAuthOptionsLinkedIn): Promise;
export declare function initSalesforce(options: TnsOAuth.ITnsOAuthOptionsSalesforce): Promise;
+export declare function initDropBox(options: TnsOAuth.ITnsOAuthOptionsDropBox): Promise;
export declare function accessToken(): string;
export declare function login(successPage?: string): Promise;
diff --git a/index.ts b/index.ts
index 06b48a5..c0cc9ea 100644
--- a/index.ts
+++ b/index.ts
@@ -10,6 +10,7 @@ import { AuthHelperGoogle } from './auth-helper-google';
import { AuthHelperUaa } from './auth-helper-uaa';
import { AuthHelperLinkedIn } from './auth-helper-linkedin';
import { AuthHelperSalesforce } from './auth-helper-salesforce';
+import { AuthHelperDropBox } from './auth-helper-dropbox';
import * as TnsOAuth from './tns-oauth-interfaces';
@@ -125,6 +126,23 @@ export function initSalesforce(options: TnsOAuth.ITnsOAuthOptionsSalesforce): Pr
});
}
+export function initDropBox(options: TnsOAuth.ITnsOAuthOptionsDropBox): Promise {
+ return new Promise(function (resolve, reject) {
+ try {
+ if (instance !== null) {
+ reject("You already ran init");
+ return;
+ }
+
+ instance = new AuthHelperDropBox(options.clientId, options.clientSecret, options.redirectUri, options.scope);
+ resolve(instance);
+ } catch (ex) {
+ console.log("Error in AuthHelperLinkedIn.init: " + ex);
+ reject(ex);
+ }
+ });
+}
+
diff --git a/tns-oauth-interfaces.d.ts b/tns-oauth-interfaces.d.ts
index 3175248..b43a164 100644
--- a/tns-oauth-interfaces.d.ts
+++ b/tns-oauth-interfaces.d.ts
@@ -22,6 +22,9 @@ export interface ITnsOAuthCredentials {
redirectUri: string;
responseType?: string;
scope: string;
+ ignoredTokenParams?: string[];
+ ignoredAuthParams?: string[];
+ skipNextTokenNav?: boolean;
}
export interface ITnsOAuthCredentialsUaa extends ITnsOAuthCredentials {
@@ -68,3 +71,8 @@ export interface ITnsOAuthOptionsSalesforce extends ITnsOAuthOptions {
redirectUri: string;
responseType: string;
}
+
+export interface ITnsOAuthOptionsDropBox extends ITnsOAuthOptions {
+ clientSecret: string;
+ redirectUri: string;
+}
diff --git a/tns-oauth.ts b/tns-oauth.ts
index 2ab7a75..ff6f84a 100644
--- a/tns-oauth.ts
+++ b/tns-oauth.ts
@@ -25,6 +25,20 @@ function getAuthHeaderFromCredentials(credentials: TnsOAuthModule.ITnsOAuthCrede
return customAuthHeader;
}
+function isIgnoredParameter(paramName: string, ignoredParameters: string[]): boolean {
+ return ignoredParameters.indexOf(paramName) > -1;
+}
+
+function setMemberIfNotIgnored(params: any, paramName: string, ignoredParams: string[], value: string): any {
+ if(!isIgnoredParameter(paramName, ignoredParams)) params[paramName] = value;
+ return params;
+}
+
+function addQueryStringIfNotIgnored(queryStr: string, paramName: string, ignoredParams: string[], value: string): string {
+ if(!isIgnoredParameter(paramName, ignoredParams)) queryStr += (queryStr.startsWith('?') ? '&' : '?') + (paramName + '=' + value);
+ return queryStr;
+}
+
/**
* Gets a token for a given resource.
@@ -43,13 +57,15 @@ function getTokenFromCode(credentials: TnsOAuthModule.ITnsOAuthCredentials, code
customAuthHeader
);
- let oauthParams = {
- grant_type: 'authorization_code',
- redirect_uri: credentials.redirectUri,
- response_mode: 'form_post',
- nonce: utils.newUUID(),
- state: 'abcd'
- };
+ credentials.ignoredTokenParams = credentials.ignoredTokenParams || [];
+
+ let oauthParams = { };
+
+ oauthParams = setMemberIfNotIgnored(oauthParams, 'grant_type', credentials.ignoredTokenParams, 'authorization_code');
+ oauthParams = setMemberIfNotIgnored(oauthParams, 'redirect_uri', credentials.ignoredTokenParams, credentials.redirectUri);
+ oauthParams = setMemberIfNotIgnored(oauthParams, 'response_mode', credentials.ignoredTokenParams, 'form_post');
+ oauthParams = setMemberIfNotIgnored(oauthParams, 'nonce', credentials.ignoredTokenParams, utils.newUUID());
+ oauthParams = setMemberIfNotIgnored(oauthParams, 'state', credentials.ignoredTokenParams, 'abcd');
return oauth2.getOAuthAccessToken(code, oauthParams);
}
@@ -71,13 +87,15 @@ export function getTokenFromRefreshToken(credentials: TnsOAuthModule.ITnsOAuthCr
customAuthHeader
);
- let oauthParams = {
- grant_type: 'refresh_token',
- redirect_uri: credentials.redirectUri,
- response_mode: 'form_post',
- nonce: utils.newUUID(),
- state: 'abcd'
- };
+ credentials.ignoredTokenParams = credentials.ignoredTokenParams || [];
+
+ let oauthParams = { };
+
+ oauthParams = setMemberIfNotIgnored(oauthParams, 'grant_type', credentials.ignoredTokenParams, 'refresh_token');
+ oauthParams = setMemberIfNotIgnored(oauthParams, 'redirect_uri', credentials.ignoredTokenParams, credentials.redirectUri);
+ oauthParams = setMemberIfNotIgnored(oauthParams, 'response_mode', credentials.ignoredTokenParams, 'form_post');
+ oauthParams = setMemberIfNotIgnored(oauthParams, 'nonce', credentials.ignoredTokenParams, utils.newUUID());
+ oauthParams = setMemberIfNotIgnored(oauthParams, 'state', credentials.ignoredTokenParams, 'abcd');
return oauth2.getOAuthAccessToken(refreshToken, oauthParams);
}
@@ -87,14 +105,19 @@ export function getTokenFromRefreshToken(credentials: TnsOAuthModule.ITnsOAuthCr
* @return {string} a fully formed uri with which authentication can be completed
*/
export function getAuthUrl(credentials: TnsOAuthModule.ITnsOAuthCredentials): string {
- return credentials.authority + credentials.authorizeEndpoint +
- '?client_id=' + credentials.clientId +
- '&response_type=code' +
- '&redirect_uri=' + credentials.redirectUri +
- '&scope=' + credentials.scope +
- '&response_mode=query' +
- '&nonce=' + utils.newUUID() +
- '&state=abcd';
+ var queryStr = '';
+
+ credentials.ignoredAuthParams = credentials.ignoredAuthParams || [];
+
+ queryStr = addQueryStringIfNotIgnored(queryStr, 'client_id', credentials.ignoredAuthParams, credentials.clientId);
+ queryStr = addQueryStringIfNotIgnored(queryStr, 'response_type', credentials.ignoredAuthParams, 'code');
+ queryStr = addQueryStringIfNotIgnored(queryStr, 'redirect_uri', credentials.ignoredAuthParams, credentials.redirectUri);
+ queryStr = addQueryStringIfNotIgnored(queryStr, 'scope', credentials.ignoredAuthParams, credentials.scope);
+ queryStr = addQueryStringIfNotIgnored(queryStr, 'response_mode', credentials.ignoredAuthParams, 'query');
+ queryStr = addQueryStringIfNotIgnored(queryStr, 'nonce', credentials.ignoredAuthParams, utils.newUUID());
+ queryStr = addQueryStringIfNotIgnored(queryStr, 'state', credentials.ignoredAuthParams, 'abcd');
+
+ return credentials.authority + credentials.authorizeEndpoint + queryStr;
}
export function getTokenFromCache() {
@@ -104,6 +127,7 @@ export function getTokenFromCache() {
export function loginViaAuthorizationCodeFlow(credentials: TnsOAuthModule.ITnsOAuthCredentials, successPage?: string): Promise {
return new Promise((resolve, reject) => {
var navCount = 0;
+ var tokenNavStarted = false;
let checkCodeIntercept = (webView, error, url): boolean => {
var retStr = '';
@@ -135,6 +159,9 @@ export function loginViaAuthorizationCodeFlow(credentials: TnsOAuthModule.ITnsOA
let errSubCode = qsObj['error_subcode'];
if (codeStr) {
try {
+ if(credentials.skipNextTokenNav && tokenNavStarted) return true;
+
+ tokenNavStarted = true;
getTokenFromCode(credentials, codeStr)
.then((response: TnsOAuthModule.ITnsOAuthTokenResult) => {
TnsOAuthTokenCache.setToken(response);
diff --git a/tsconfig.json b/tsconfig.json
index ad6ff72..83e5d73 100755
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -29,6 +29,7 @@
"auth-helper-office365.ts",
"auth-helper-uaa.ts",
"auth-helper-linkedin.ts",
+ "auth-helper-dropbox.ts",
"index.ts",
"tns-oauth.ts",
"tns-oauth-page-provider.ts",