├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── package.json ├── src ├── core.ts ├── oauth.ts ├── platform │ ├── browser.ts │ └── cordova.ts ├── provider.ts ├── provider │ ├── facebook.ts │ ├── google.ts │ ├── imgur.ts │ ├── instagram.ts │ ├── linkedin.ts │ ├── meetup.ts │ ├── spotify.ts │ ├── strava.ts │ └── vk.ts └── utility.ts ├── test └── index.html └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | 4 | .DS_Store* 5 | Thumbs.db* 6 | ~* 7 | 8 | platform 9 | provider 10 | *.js 11 | *.d.ts -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | .travis.yml 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - 0.12 5 | before_script: 6 | - npm install 7 | - npm run tsc 8 | notifications: 9 | on_success: never 10 | on_failure: always 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Nic Raboy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/nraboy/ng2-cordova-oauth.svg?branch=master)](https://travis-ci.org/nraboy/ng2-cordova-oauth) 2 | [![PayPal](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://paypal.me/nraboy) 3 | [![Bitcoin](https://img.shields.io/badge/bitcoin-donate-red.svg)](bitcoin://1M8SKTepmgA2KAUSZc7LpXN1owaky1DjNM) 4 | 5 | # Angular 2 Cordova Oauth 6 | 7 | ng2-cordova-oauth is an Oauth library which easily integrates in Angular2/Ionic2 or any other WEB or Cordova applications. The purpose of this library is to quickly and easily obtain an access token from various web services to use their APIs. 8 | 9 | ## Donations 10 | 11 | If you found this project useful, please consider donating some Bitcoin to the following address: 12 | 13 | [1M8SKTepmgA2KAUSZc7LpXN1owaky1DjNM](bitcoin://1M8SKTepmgA2KAUSZc7LpXN1owaky1DjNM?amount=0.008) 14 | 15 | ## Requirements 16 | 17 | For Cordova application: 18 | * Apache Cordova 5+ 19 | * [Apache Cordova InAppBrowser Plugin](http://cordova.apache.org/docs/en/3.0.0/cordova_inappbrowser_inappbrowser.md.html) 20 | * [Apache Cordova Whitelist Plugin](https://github.com/apache/cordova-plugin-whitelist) 21 | 22 | For Web application: 23 | * webpack, systemjs or amd loaders 24 | 25 | 26 | ## Installing ng2-cordova-oauth Into Your Project 27 | 28 | ### Installing 29 | 30 | From the root of your Apache Cordova project, execute the following: 31 | 32 | ``` 33 | npm install ng2-cordova-oauth --save 34 | ``` 35 | 36 | This will install ng2-cordova-oauth and its dependencies. 37 | 38 | ### Injecting: 39 | 40 | There are 2 types of entities in the library: Platform (i.e., Cordova, Browser) and Provider (i.e., Facebook, LinkedIn, etc.). Each provider has it's own class. 41 | You need to inject the Platform class into every class in which you wish to use them. For example, if you wish to use Facebook oauth in a particular class, it would look something like: 42 | 43 | ```javascript 44 | import {Facebook, Google} from 'ng2-cordova-oauth/core'; 45 | import {OauthBrowser} from 'ng2-cordova-oauth/platform/browser' 46 | // or 47 | import {OauthCordova} from 'ng2-cordova-oauth/platform/cordova' 48 | ``` 49 | 50 | Alternatively you can use Angular2 Injector in order to provide platform specific service for all components: 51 | ```js 52 | import {bootstrap} from '@angular/platform-browser-dynamic' 53 | import {App} from './app.component' 54 | import {OauthCordova} from 'ng2-cordova-oauth/platform/cordova' 55 | import {Oauth} from 'ng2-cordova-oauth/oauth' 56 | 57 | bootstrap(App, [ 58 | { provide: Oauth, useClass: OauthCordova } 59 | ]) 60 | 61 | // and later in component 62 | 63 | @Component({ 64 | selector: 'my-component' 65 | }) 66 | class MyComponent { 67 | constructor(oauth: Oauth) { 68 | this.oauth = oauth 69 | } 70 | } 71 | ``` 72 | 73 | 74 | ## Using ng2-cordova-oauth In Your Project 75 | 76 | Each web service API acts independently in this library. However, when configuring each web service, one thing must remain consistent. 77 | 78 | Currently it supports several oAuth providers: Facebook, Instagram, LinkedIn, Google, Meetup, Imgur. Example of creating oAuth provider: 79 | 80 | ```js 81 | const provider = new Facebook({ 82 | clientId: string, 83 | appScope?: string[], 84 | redirectUri?: string, 85 | responseType?: string, 86 | authType?: string 87 | }); 88 | ``` 89 | 90 | Each API call returns a promise. The success callback will provide a response object and the error callback will return an `Error` object. Not all providers use implicit grants. Any provider that uses an explicit grant will return a `code` rather than an `access_token`. The `code` must be 91 | further exchanged server side for an `access_token`. This is for the safety of your users. 92 | 93 | ```js 94 | const oauth = new OauthCordova(); 95 | const provider = new Facebook({ 96 | clientId: "CLIENT_ID_HERE", 97 | appScope: ["email"] 98 | }) 99 | 100 | oauth.logInVia(provider).then((success) => { 101 | console.log(JSON.stringify(success)); 102 | }, (error) => { 103 | console.log(JSON.stringify(error)); 104 | }); 105 | ``` 106 | 107 | As of Apache Cordova 5.0.0, the [whitelist plugin](https://blog.nraboy.com/2015/05/whitelist-external-resources-for-use-in-ionic-framework/) must be used in order to reach external web services. 108 | 109 | Now this library can work with a web browser, ionic serve, or ionic view in case if you use `OauthPlatform` service but do not forget to replace it with correct one for cordova project (i.e., `OauthCordova`) 110 | 111 | ### Important Note About Google 112 | 113 | Google, as of October 2016, has started blocking requests from web views commonly found in hybrid applications. For this reason, support for Google has been removed from this library. 114 | 115 | More information can be found at: 116 | 117 | [https://developers.googleblog.com/2016/08/modernizing-oauth-interactions-in-native-apps.html](https://developers.googleblog.com/2016/08/modernizing-oauth-interactions-in-native-apps.html) 118 | 119 | ## A Working Example 120 | 121 | ```javascript 122 | import {Component} from '@angular/core'; 123 | import {NavController, Platform} from 'ionic-angular'; 124 | import {Facebook, Google, LinkedIn} from "ng2-cordova-oauth/core"; 125 | import {OauthCordova} from 'ng2-cordova-oauth/platform/cordova'; 126 | 127 | @Component({ 128 | templateUrl: 'build/pages/home/home.html' 129 | }) 130 | export class HomePage { 131 | 132 | private oauth: OauthCordova = new OauthCordova(); 133 | private facebookProvider: Facebook = new Facebook({ 134 | clientId: "CLIENT_ID_HERE", 135 | appScope: ["email"] 136 | }) 137 | 138 | constructor(private navCtrl: NavController, private platform: Platform) { } 139 | 140 | public facebook() { 141 | this.platform.ready().then(() => { 142 | this.oauth.logInVia(this.facebookProvider).then(success => { 143 | console.log("RESULT: " + JSON.stringify(success)); 144 | }, error => { 145 | console.log("ERROR: ", error); 146 | }); 147 | }); 148 | } 149 | 150 | } 151 | ``` 152 | Alternatively you can inject `OauthCordova` in constructor as shown in examples above. 153 | 154 | ### Custom browser window options 155 | 156 | Browser's `window.open` and Cordova's InAppBrowser supports bunch of options which can be passed as a second argument to `logInVia`. For example if you don't know want to clear session cache, or place toolbar at the top for iOS: 157 | ```js 158 | new OauthCordova().logInVia(facebookProvider, { 159 | clearsessioncache: 'no', 160 | toolbarposition: 'top' 161 | }) 162 | ``` 163 | 164 | the list of all available options can be found: 165 | * https://developer.mozilla.org/en-US/docs/Web/API/Window/open for web apps 166 | * https://github.com/apache/cordova-plugin-inappbrowser#cordovainappbrowseropen for cordova apps 167 | 168 | 169 | ## Version History 170 | 171 | Coming soon... 172 | 173 | 174 | ## Contribution Rules 175 | 176 | All contributions must be made via the `development` branch. This keeps the project more maintainable in terms of versioning as well as code control. 177 | 178 | 179 | ## Have a question or found a bug (compliments work too)? 180 | 181 | This project is maintained by **Nic Raboy**. 182 | 183 | Tweet Nic Raboy on Twitter - [@nraboy](https://www.twitter.com/nraboy) 184 | 185 | 186 | ## Resources 187 | 188 | Ionic 2 - [http://www.ionicframework.com](http://www.ionicframework.com) 189 | 190 | Angular 2 - [https://www.angular.io](https://www.angular.io) 191 | 192 | Apache Cordova - [http://cordova.apache.org](http://cordova.apache.org) 193 | 194 | Nic Raboy's Code Blog - [https://www.thepolyglotdeveloper.com](https://www.thepolyglotdeveloper.com) 195 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng2-cordova-oauth", 3 | "version": "0.0.8", 4 | "description": "Connect to Oauth providers using Apache Cordova, Angular 2, and the InAppBrowser plugin", 5 | "author": { 6 | "name": "Nic Raboy", 7 | "url": "https://www.nraboy.com" 8 | }, 9 | "homepage": "https://www.thepolyglotdeveloper.com", 10 | "devDependencies": { 11 | "typescript": "^1.7.5" 12 | }, 13 | "keywords": [ 14 | "angular 2", 15 | "oauth", 16 | "api", 17 | "apache cordova", 18 | "phonegap", 19 | "ionic framework", 20 | "ionic 2", 21 | "typescript" 22 | ], 23 | "license": "MIT", 24 | "scripts": { 25 | "build.commonjs": "tsc", 26 | "build.system": "tsc --outFile ng2-cordova-oauth.system.js --module system", 27 | "build": "npm run build.system && npm run build.commonjs", 28 | "tsc": "npm run build.commonjs" 29 | }, 30 | "bugs": { 31 | "url": "https://github.com/nraboy/ng2-cordova-oauth/issues" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/core.ts: -------------------------------------------------------------------------------- 1 | export * from "./oauth" 2 | export * from "./provider/facebook" 3 | export * from "./provider/google" 4 | export * from "./provider/imgur" 5 | export * from "./provider/instagram" 6 | export * from "./provider/meetup" 7 | export * from "./provider/linkedin" 8 | export * from "./provider/strava" 9 | export * from "./provider/vk" 10 | -------------------------------------------------------------------------------- /src/oauth.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Angular 2 (ng2) Cordova Oauth 3 | * Created by Nic Raboy 4 | * http://www.nraboy.com 5 | */ 6 | 7 | import { OAuthProvider } from './provider'; 8 | import { utils } from './utility'; 9 | 10 | /* 11 | * The main driver class for connections to each of the providers. 12 | */ 13 | export class Oauth { 14 | defaultWindowOptions: Object = {}; 15 | 16 | login(provider: OAuthProvider, windowOptions: Object = {}) { 17 | console.warn(` 18 | new CordovaOauth().login(...) is deprecated and will be removed in the next release. 19 | Please use new CordovaOauth().logInVia(...) instead. 20 | `) 21 | return this.logInVia(provider, windowOptions) 22 | } 23 | 24 | logInVia(provider: OAuthProvider, windowOptions: Object = {}) { 25 | const url = provider.dialogUrl(); 26 | 27 | return this.openDialog(url, utils.defaults(windowOptions, this.defaultWindowOptions), { 28 | resolveOnUri: provider.options.redirectUri, 29 | providerName: provider.name 30 | }).then((event) => { 31 | return provider.parseResponseInUrl(event.url); 32 | }) 33 | } 34 | 35 | protected serializeOptions(options: Object) { 36 | const chunks = []; 37 | 38 | for (const prop in options) { 39 | if (options.hasOwnProperty(prop)) { 40 | chunks.push(`${prop}=${options[prop]}`); 41 | } 42 | } 43 | 44 | return chunks.join(','); 45 | } 46 | 47 | protected openDialog(url: string, windowParams: Object, options: any = {}): Promise { 48 | return Promise.reject(new Error('Not implemented')); 49 | } 50 | } 51 | 52 | /* 53 | * All providers must have the functions and variables that exist in this interface. Keeps 54 | * consistency between the providers. 55 | */ 56 | export interface IOauthProvider { 57 | parseResponseInUrl(url: string): Object; 58 | } 59 | -------------------------------------------------------------------------------- /src/platform/browser.ts: -------------------------------------------------------------------------------- 1 | import { Oauth } from '../oauth'; 2 | import { utils } from '../utility'; 3 | 4 | export class OauthBrowser extends Oauth { 5 | static WATCH_POPUP_TIMEOUT = 100 6 | 7 | defaultWindowOptions = { 8 | width: 600, 9 | location: 1, 10 | toolbar: 0, 11 | }; 12 | 13 | protected openDialog(url: string, params: Object, options: any = {}) { 14 | const windowParams = this.addWindowRect(utils.defaults({ title: 'Authentication' }, params)); 15 | const title = windowParams.title; 16 | delete windowParams.title; 17 | 18 | const popup = window.open(url, title, this.serializeOptions(windowParams)) 19 | const watchDelay = (this.constructor).WATCH_POPUP_TIMEOUT; 20 | 21 | return new Promise((resolve, reject) => { 22 | if (typeof popup.focus === 'function') { 23 | popup.focus(); 24 | } 25 | 26 | setTimeout(function watchPopup() { 27 | try { 28 | if (popup.closed) { 29 | return reject(new Error(`The "${options.providerName}" sign in flow was canceled`)); 30 | } 31 | 32 | if (popup.location.href.indexOf(options.resolveOnUri) === 0) { 33 | popup.close(); 34 | resolve({ url: popup.location.href }); 35 | } 36 | } catch (e) { 37 | } 38 | 39 | setTimeout(watchPopup, watchDelay); 40 | }, watchDelay); 41 | }); 42 | } 43 | 44 | private addWindowRect(params) { 45 | const root = document.documentElement; 46 | let screenX = typeof window.screenX !== 'undefined' ? window.screenX : window.screenLeft; 47 | const screenY = typeof window.screenY !== 'undefined' ? window.screenY : window.screenTop; 48 | const outerWidth = typeof window.outerWidth !== 'undefined' ? window.outerWidth : root.clientWidth; 49 | const outerHeight = typeof window.outerHeight !== 'undefined' ? window.outerHeight : root.clientHeight - 22; 50 | 51 | screenX = screenX < 0 ? window.screen.width + screenX : screenX; 52 | params.height = Math.floor(outerHeight * 0.8); 53 | params.left = Math.floor(screenX + (outerWidth - params.width) / 2); 54 | params.top = Math.floor(screenY + (outerHeight - params.height) / 2.5); 55 | 56 | return params; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/platform/cordova.ts: -------------------------------------------------------------------------------- 1 | import { Oauth } from '../oauth'; 2 | 3 | declare var window: any; 4 | 5 | function ensureEnvIsValid() { 6 | if (!window.cordova) { 7 | throw new Error('Cannot authenticate via a web browser'); 8 | } 9 | 10 | if (!window.cordova.InAppBrowser) { 11 | throw new Error('The Apache Cordova InAppBrowser plugin was not found and is required'); 12 | } 13 | } 14 | 15 | export class OauthCordova extends Oauth { 16 | defaultWindowOptions = { 17 | location: 'no', 18 | clearsessioncache: 'yes', 19 | clearcache: 'yes' 20 | }; 21 | 22 | protected openDialog(url: string, windowParams: Object, options: any = {}) { 23 | const params = this.serializeOptions(windowParams); 24 | 25 | return new Promise((resolve, reject) => { 26 | try { 27 | ensureEnvIsValid(); 28 | } catch (error) { 29 | return reject(error); 30 | } 31 | 32 | const browserRef = window.cordova.InAppBrowser.open(url, '_blank', params); 33 | const exitListener = () => reject(new Error(`The "${options.providerName}" sign in flow was canceled`)); 34 | 35 | browserRef.addEventListener('loaderror', () => { 36 | browserRef.removeEventListener('exit', exitListener); 37 | browserRef.close(); 38 | reject(new Error(`Error loading login page of "${options.providerName}"`)); 39 | }); 40 | 41 | browserRef.addEventListener('loadstart', (event) => { 42 | if (event.url.indexOf(options.resolveOnUri) === 0) { 43 | browserRef.removeEventListener('exit', exitListener); 44 | browserRef.close(); 45 | resolve(event) 46 | } 47 | }) 48 | 49 | return browserRef.addEventListener('exit', exitListener); 50 | }) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/provider.ts: -------------------------------------------------------------------------------- 1 | import { utils } from './utility'; 2 | import { IOauthProvider } from './oauth'; 3 | 4 | declare var window: any; 5 | 6 | export interface IOAuthOptions { 7 | clientId?: string; 8 | appScope?: string[]; 9 | redirectUri?: string; 10 | responseType?: string; 11 | state?: string; 12 | } 13 | 14 | const DEFAULTS = { 15 | redirectUri: 'http://localhost/callback' 16 | }; 17 | 18 | export class OAuthProvider implements IOauthProvider { 19 | options: IOAuthOptions; 20 | protected APP_SCOPE_DELIMITER: string = ','; 21 | protected authUrl: string = ''; 22 | protected defaults: Object = {}; 23 | 24 | constructor(options: IOAuthOptions = {}) { 25 | this.options = utils.defaults(options, DEFAULTS); 26 | } 27 | 28 | get name() { 29 | return this.constructor.name || this.authUrl; 30 | } 31 | 32 | parseResponseInUrl(url) { 33 | const response = utils.parseQueryString(url); 34 | 35 | if (!this.isValid(response)) { 36 | const error = new Error(`Problem authenticating with ${this.name}`); 37 | 38 | Object.defineProperty(error, 'response', { value: response }); 39 | throw error; 40 | } 41 | 42 | return response; 43 | } 44 | 45 | dialogUrl() { 46 | return this.optionsToDialogUrl(this.options); 47 | } 48 | 49 | protected optionsToDialogUrl(options: any): string { 50 | utils.defaults(options, this.defaults) 51 | let url = `${this.authUrl}?client_id=${options.clientId}&redirect_uri=${options.redirectUri}`; 52 | 53 | if (options.appScope) { 54 | url += `&scope=${this.serializeAppScope(options.appScope)}`; 55 | } 56 | 57 | if (options.state) { 58 | url += `&state=${options.state}`; 59 | } 60 | 61 | if (options.responseType) { 62 | url += `&response_type=${options.responseType}`; 63 | } 64 | 65 | return url; 66 | } 67 | 68 | protected serializeAppScope(scope) { 69 | return typeof scope.join === 'function' ? scope.join(this.APP_SCOPE_DELIMITER) : scope; 70 | } 71 | 72 | protected isValid(response) { 73 | return !response.error && (response.code || response['access_token']); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/provider/facebook.ts: -------------------------------------------------------------------------------- 1 | import { OAuthProvider, IOAuthOptions } from "../provider"; 2 | 3 | /* 4 | * Configuration options for using Facebook oauth 5 | */ 6 | export interface IFacebookOptions extends IOAuthOptions { 7 | authType?: string; 8 | } 9 | 10 | export class Facebook extends OAuthProvider { 11 | 12 | options: IFacebookOptions; 13 | protected authUrl: string = 'https://www.facebook.com/v2.0/dialog/oauth'; 14 | protected defaults: Object = { 15 | responseType: 'token' 16 | }; 17 | 18 | constructor(options: IFacebookOptions = {}) { 19 | super(options); 20 | 21 | if (!options.appScope || options.appScope.length <= 0) { 22 | throw new Error(`A ${this.name} app scope must exist`); 23 | } 24 | } 25 | 26 | protected optionsToDialogUrl(options) { 27 | let url = super.optionsToDialogUrl(options); 28 | 29 | if (options.authType) { 30 | url += `&auth_type=${options.authType}`; 31 | } 32 | 33 | return url; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/provider/google.ts: -------------------------------------------------------------------------------- 1 | import { OAuthProvider, IOAuthOptions } from "../provider"; 2 | 3 | /* 4 | * Configuration options for using Google oauth 5 | * @deprecated 6 | */ 7 | export interface IGoogleOptions extends IOAuthOptions { 8 | } 9 | 10 | export class Google extends OAuthProvider { 11 | 12 | options: IGoogleOptions; 13 | protected authUrl: string = 'https://accounts.google.com/o/oauth2/auth'; 14 | protected APP_SCOPE_DELIMITER = ' '; 15 | protected defaults: Object = { 16 | responseType: 'token' 17 | }; 18 | 19 | constructor(options: IGoogleOptions = {}) { 20 | super(options); 21 | 22 | if (!options.appScope || options.appScope.length <= 0) { 23 | throw new Error(`A ${this.name} app scope must exist`); 24 | } 25 | } 26 | 27 | protected optionsToDialogUrl(options) { 28 | return super.optionsToDialogUrl(options) + '&approval_prompt=force' 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/provider/imgur.ts: -------------------------------------------------------------------------------- 1 | import { OAuthProvider, IOAuthOptions } from "../provider"; 2 | 3 | /* 4 | * Configuration options for using Imgur oauth 5 | * @deprecated 6 | */ 7 | export interface IImgurOptions extends IOAuthOptions { 8 | } 9 | 10 | export class Imgur extends OAuthProvider { 11 | 12 | options: IImgurOptions; 13 | protected authUrl: string = 'https://api.imgur.com/oauth2/authorize'; 14 | protected defaults: Object = { 15 | responseType: 'token' 16 | }; 17 | 18 | constructor(options: IImgurOptions = {}) { 19 | super(options); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/provider/instagram.ts: -------------------------------------------------------------------------------- 1 | import { OAuthProvider, IOAuthOptions } from "../provider"; 2 | 3 | /* 4 | * Configuration options for using Instagram oauth 5 | * @deprecated 6 | */ 7 | export interface IInstagramOptions extends IOAuthOptions { 8 | } 9 | 10 | export class Instagram extends OAuthProvider { 11 | 12 | options: IInstagramOptions; 13 | protected authUrl: string = 'https://api.instagram.com/oauth/authorize'; 14 | protected APP_SCOPE_DELIMITER: string = '+'; 15 | protected defaults: Object = { 16 | responseType: 'token' 17 | }; 18 | 19 | constructor(options: IInstagramOptions = {}) { 20 | super(options); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/provider/linkedin.ts: -------------------------------------------------------------------------------- 1 | import { OAuthProvider } from "../provider"; 2 | 3 | export class LinkedIn extends OAuthProvider { 4 | protected authUrl: string = 'https://www.linkedin.com/oauth/v2/authorization' 5 | protected APP_SCOPE_DELIMITER = ' '; 6 | protected defaults: Object = { 7 | responseType: 'code' 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /src/provider/meetup.ts: -------------------------------------------------------------------------------- 1 | import { OAuthProvider, IOAuthOptions } from "../provider"; 2 | 3 | /* 4 | * Configuration options for using Meetup oauth 5 | * @deprecated 6 | */ 7 | export interface IMeetupOptions extends IOAuthOptions { 8 | } 9 | 10 | export class Meetup extends OAuthProvider { 11 | 12 | options: IMeetupOptions; 13 | protected authUrl: string = 'https://secure.meetup.com/oauth2/authorize/'; 14 | protected defaults: Object = { 15 | responseType: 'token' 16 | }; 17 | 18 | constructor(options: IMeetupOptions = {}) { 19 | super(options); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/provider/spotify.ts: -------------------------------------------------------------------------------- 1 | // Spotify web api authorization guide and scopes 2 | // https://developer.spotify.com/web-api/authorization-guide 3 | // https://developer.spotify.com/web-api/using-scopes/ 4 | 5 | import { OAuthProvider } from "../provider"; 6 | 7 | export class Spotify extends OAuthProvider { 8 | protected authUrl: string = 'https://accounts.spotify.com/authorize'; 9 | protected APP_SCOPE_DELIMITER = ' '; 10 | protected defaults: Object = { 11 | responseType: 'token' 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/provider/strava.ts: -------------------------------------------------------------------------------- 1 | import { OAuthProvider, IOAuthOptions } from "../provider"; 2 | 3 | export class Strava extends OAuthProvider { 4 | protected authUrl: string = 'https://www.strava.com/oauth/authorize'; 5 | protected defaults: Object = { 6 | responseType: 'code' 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /src/provider/vk.ts: -------------------------------------------------------------------------------- 1 | import { OAuthProvider, IOAuthOptions } from "../provider"; 2 | import { utils } from '../utility'; 3 | 4 | /* 5 | * Configuration options for using VK oauth 6 | * @deprecated 7 | */ 8 | export interface IVKOptions extends IOAuthOptions { 9 | v?: string; 10 | display?: string; 11 | revoke?: string; 12 | } 13 | 14 | export class VK extends OAuthProvider { 15 | options: IVKOptions; 16 | protected authUrl: string = 'https://oauth.vk.com/authorize'; 17 | protected defaults: Object = { 18 | responseType: 'token', 19 | redirectUri: 'https://oauth.vk.com/blank.html' 20 | }; 21 | 22 | constructor(options: IVKOptions = {}) { 23 | super(options); 24 | 25 | if (!options.appScope || options.appScope.length <= 0) { 26 | throw new Error(`A ${this.name} app scope must exist`); 27 | } 28 | } 29 | 30 | protected optionsToDialogUrl(options: any): string { 31 | utils.defaults(options, this.defaults); 32 | let url = super.optionsToDialogUrl(options); 33 | 34 | if (options.display) { 35 | url += `&display=${options.display}`; 36 | } 37 | 38 | if (options.v) { 39 | url += `&v=${options.v}`; 40 | } 41 | 42 | if (options.revoke) { 43 | url += `&revoke=${options.revoke}`; 44 | } 45 | return url; 46 | } 47 | } -------------------------------------------------------------------------------- /src/utility.ts: -------------------------------------------------------------------------------- 1 | export const utils = { 2 | 3 | parseQueryString(url: string): Object { 4 | const values = url.split(/[?#]{1,2}/)[1].split('&') 5 | 6 | return values.reduce((map, value) => { 7 | const [paramName, paramValue] = value.split('=') 8 | map[decodeURIComponent(paramName)] = decodeURIComponent(paramValue) 9 | 10 | return map 11 | }, {}) 12 | }, 13 | 14 | defaults(target: Object, ...sources: Object[]) { 15 | sources.forEach(source => { 16 | for (const prop in source) { 17 | if (!target.hasOwnProperty(prop)) { 18 | target[prop] = source[prop]; 19 | } 20 | } 21 | }); 22 | 23 | return target; 24 | } 25 | 26 | }; 27 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | test me 5 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
32 | 33 | 34 | 35 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "emitDecoratorMetadata": true, 4 | "experimentalDecorators": true, 5 | "target": "es5", 6 | "module": "commonjs", 7 | "sourceMap": false, 8 | "removeComments": false, 9 | "noImplicitAny": false, 10 | "declaration": true, 11 | "outDir": "." 12 | }, 13 | "files": [ 14 | "src/core.ts", 15 | "src/oauth.ts", 16 | "src/utility.ts", 17 | "src/provider/facebook.ts", 18 | "src/provider/google.ts", 19 | "src/provider/imgur.ts", 20 | "src/provider/instagram.ts", 21 | "src/provider/meetup.ts", 22 | "src/provider/spotify.ts", 23 | "src/provider/linkedin.ts", 24 | "src/platform/browser.ts", 25 | "src/platform/cordova.ts", 26 | "node_modules/typescript/lib/lib.es6.d.ts" 27 | ], 28 | "exclude": [ 29 | "node_modules" 30 | ] 31 | } 32 | --------------------------------------------------------------------------------