Skip to content
This repository has been archived by the owner on Jan 20, 2024. It is now read-only.

Commit

Permalink
Allow getToken uri to be a partial URL object
Browse files Browse the repository at this point in the history
  • Loading branch information
blakeembrey committed Jan 3, 2017
1 parent 7a8e38a commit a8ce208
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 19 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ app.get('/auth/github/callback', function (req, res) {
})
```

**P.S.** The `getToken` URI parameter can be an object containing `pathname` and `query` properties.

### [Implicit Grant](http://tools.ietf.org/html/rfc6749#section-4.2)

> The implicit grant type is used to obtain access tokens (it does not support the issuance of refresh tokens) and is optimized for public clients known to operate a particular redirection URI. These clients are typically implemented in a browser using a scripting language such as JavaScript.
Expand Down Expand Up @@ -137,6 +139,8 @@ window.oauth2Callback = function (uri) {
window.open(githubAuth.token.getUri())
```

**P.S.** The `getToken` URI parameter can be an object containing `pathname`, `query` and `hash` properties.

### [Resource Owner Password Credentials Grant](http://tools.ietf.org/html/rfc6749#section-4.3)

> The resource owner password credentials grant type is suitable in cases where the resource owner has a trust relationship with the client, such as the device operating system or a highly privileged application. The authorization server should take special care when enabling this grant type and only allow it when other flows are not viable.
Expand Down
14 changes: 12 additions & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ declare namespace ClientOAuth2 {
};
}

export interface UrlObject {
hash?: string | {
[key: string]: string | string[];
};
query?: string | {
[key: string]: string | string[];
}
pathname?: string;
}

export class Token {
client: ClientOAuth2;
data: Data;
Expand All @@ -65,13 +75,13 @@ declare namespace ClientOAuth2 {
export class CodeFlow {
constructor(client: ClientOAuth2);
getUri(options?: Options): string;
getToken(uri: string, options?: Options): Promise<Token>;
getToken(uri: string | UrlObject, options?: Options): Promise<Token>;
}

export class TokenFlow {
constructor(client: ClientOAuth2);
getUri(options?: Options): string;
getToken(uri: string, options?: Options): Promise<Token>;
getToken(uri: string | UrlObject, options?: Options): Promise<Token>;
}

export class OwnerFlow {
Expand Down
38 changes: 21 additions & 17 deletions src/client-oauth2.js
Original file line number Diff line number Diff line change
Expand Up @@ -457,32 +457,34 @@ TokenFlow.prototype.getUri = function (options) {
/**
* Get the user access token from the uri.
*
* @param {string} uri
* @param {Object} [options]
* @param {string|Object} uri
* @param {Object} [options]
* @return {Promise}
*/
TokenFlow.prototype.getToken = function (uri, options) {
options = extend(this.client.options, options)

var url = Url.parse(uri)
var url = typeof uri === 'object' ? uri : Url.parse(uri, true)
var expectedUrl = Url.parse(options.redirectUri)

if (url.pathname !== expectedUrl.pathname) {
return Promise.reject(new TypeError('Should match redirect uri: ' + uri))
if (typeof url.pathname === 'string' && url.pathname !== expectedUrl.pathname) {
return Promise.reject(
new TypeError('Redirected path should match configured path, but got: ' + url.pathname)
)
}

// If no query string or fragment exists, we won't be able to parse
// any useful information from the uri.
if (!url.hash && !url.search) {
if (!url.hash && !url.query) {
return Promise.reject(new TypeError('Unable to process uri: ' + uri))
}

// Extract data from both the fragment and query string. The fragment is most
// important, but the query string is also used because some OAuth 2.0
// implementations (Instagram) have a bug where state is passed via query.
var data = extend(
url.query ? Querystring.parse(url.query) : {},
url.hash ? Querystring.parse(url.hash.substr(1)) : {}
typeof url.query === 'string' ? Querystring.parse(url.query) : (url.query || {}),
typeof url.hash === 'string' ? Querystring.parse(url.hash.substr(1)) : (url.hash || {})
)

var err = getAuthError(data)
Expand Down Expand Up @@ -571,8 +573,8 @@ CodeFlow.prototype.getUri = function (options) {
* Get the code token from the redirected uri and make another request for
* the user access token.
*
* @param {string} uri
* @param {Object} [options]
* @param {string|Object} uri
* @param {Object} [options]
* @return {Promise}
*/
CodeFlow.prototype.getToken = function (uri, options) {
Expand All @@ -587,26 +589,28 @@ CodeFlow.prototype.getToken = function (uri, options) {
'accessTokenUri'
])

var url = Url.parse(uri)
var url = typeof uri === 'object' ? uri : Url.parse(uri, true)
var expectedUrl = Url.parse(options.redirectUri)

if (url.pathname !== expectedUrl.pathname) {
return Promise.reject(new TypeError('Should match redirect uri: ' + uri))
if (typeof url.pathname === 'string' && url.pathname !== expectedUrl.pathname) {
return Promise.reject(
new TypeError('Redirected path should match configured path, but got: ' + url.pathname)
)
}

if (!url.search) {
if (!url.query) {
return Promise.reject(new TypeError('Unable to process uri: ' + uri))
}

var data = Querystring.parse(url.query)
var data = typeof url.query === 'string' ? Querystring.parse(url.query) : (url.query || {})
var err = getAuthError(data)

if (err) {
return Promise.reject(err)
}

if (options.state && data.state !== options.state) {
return Promise.reject(new TypeError('Invalid state:' + data.state))
if (options.state != null && data.state !== options.state) {
return Promise.reject(new TypeError('Invalid state: ' + data.state))
}

// Check whether the response code is set.
Expand Down

0 comments on commit a8ce208

Please sign in to comment.