Skip to content

Commit

Permalink
Add authorize method
Browse files Browse the repository at this point in the history
  • Loading branch information
pgom committed Mar 22, 2016
1 parent 6519e27 commit 36d10ce
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 2 deletions.
41 changes: 41 additions & 0 deletions src/providers/oauth-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import angular from 'angular';
import queryString from 'query-string';

var defaults = {
authorizePath: '/oauth2/authorize',
baseUrl: null,
clientId: null,
clientSecret: null,
Expand All @@ -15,6 +16,7 @@ var defaults = {
};

var requiredKeys = [
'authorizePath',
'baseUrl',
'clientId',
'grantPath',
Expand Down Expand Up @@ -60,6 +62,11 @@ function OAuthProvider() {
config.baseUrl = config.baseUrl.slice(0, -1);
}

// Add `authorizePath` facing slash.
if('/' !== config.authorizePath[0]) {
config.authorizePath = `/${config.authorizePath}`;
}

// Add `grantPath` facing slash.
if('/' !== config.grantPath[0]) {
config.grantPath = `/${config.grantPath}`;
Expand Down Expand Up @@ -92,6 +99,40 @@ function OAuthProvider() {
}
}

/**
* Requests a authorization for an application based on clientId, scope and state
*
* @param {string} clientId - Application `clientId`
* @param {string} scope - Scope(s) defined for the application
* @param {string} state - Randomly generated `state` string
* @return {promise} A response promise.
*/

authorize(clientId, scope, state) {
// Check if `clientId` is defined.
if (!clientId) {
throw new Error('Missing parameter: clientId.');
}

const data = {
client_id: clientId,
response_type: 'code'
};

if (scope) {
data.scope = scope;
}

if (state) {
data.state = state;
}

const qs = queryString.stringify(data);
const url = `${config.baseUrl}${config.authorizePath}?${qs}`;

return $http.get(url);
}

/**
* Verifies if the `user` is authenticated or not based on the `token`
* cookie.
Expand Down
90 changes: 88 additions & 2 deletions test/unit/providers/oauth-provider.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@

describe('OAuthProvider', function() {
var defaults = {
authorizePath: '/oauth2/authorize',
baseUrl: 'https://api.website.com',
clientId: 'CLIENT_ID',
clientSecret: 'CLIENT_SECRET',
grantPath: '/oauth2/token',
revokePath: '/oauth2/revoke',
clientSecret: 'CLIENT_SECRET'
redirectUrl: 'https://website.com',
revokePath: '/oauth2/revoke'
};

describe('configure()', function() {
Expand Down Expand Up @@ -48,6 +50,25 @@ describe('OAuthProvider', function() {
}
});

it('should throw an error if `authorizePath` param is empty', function() {
try {
provider.configure(_.defaults({ authorizePath: null }, defaults));

should.fail();
} catch(e) {
e.should.be.an.instanceOf(Error);
e.message.should.match(/authorizePath/);
}
});

it('should add facing slash from `authorizePath`', function() {
var config = provider.configure(_.defaults({
authorizePath: 'oauth2/authorize'
}, defaults));

config.authorizePath.should.equal('/oauth2/authorize');
});

it('should throw an error if `baseUrl` param is empty', function() {
try {
provider.configure(_.omit(defaults, 'baseUrl'));
Expand Down Expand Up @@ -137,6 +158,71 @@ describe('OAuthProvider', function() {
OAuthToken.removeToken();
}));

describe('authorize()', function() {
var data = {
client_id: defaults.clientId,
response_type: 'code',
scope: 'foo:bar',
state: 'state_hash'
};

it('should throw an error if `clientId` is missing', inject(function(OAuth) {
try {
OAuth.authorize();

should.fail();
} catch(e) {
e.should.be.an.instanceOf(Error);
e.message.should.match(/clientId/);
}
}));

it('should call `queryString.stringify` with default `data` if `state` and `scope` are not provided', inject(function(OAuth) {
sinon.spy(queryString, 'stringify');

OAuth.authorize(data.client_id);

queryString.stringify.callCount.should.equal(1);
queryString.stringify.firstCall.args.should.have.lengthOf(1);
queryString.stringify.firstCall.args[0].should.eql({
client_id: data.client_id,
response_type: 'code'
});

queryString.stringify.restore();
}));

it('should call `queryString.stringify` with provided `state` and `scope`', inject(function(OAuth) {
sinon.spy(queryString, 'stringify');

OAuth.authorize(data.client_id, data.scope, data.state);

queryString.stringify.callCount.should.equal(1);
queryString.stringify.firstCall.args.should.have.lengthOf(1);
queryString.stringify.firstCall.args[0].should.eql({
client_id: data.client_id,
response_type: 'code',
scope: data.scope,
state: data.state
});

queryString.stringify.restore();
}));

it('should call `$http.get` with url containing the stringified `data`', inject(function($httpBackend, OAuth) {
const qs = queryString.stringify(data);

$httpBackend.expectGET(`${defaults.baseUrl}${defaults.authorizePath}?${qs}`).respond(200, 'foobar');

OAuth.authorize(data.client_id, data.scope, data.state);

$httpBackend.flush();

$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
}));
});

describe('isAuthenticated()', function() {
it('should be true when there is a stored `token` cookie', inject(function(OAuth, OAuthToken) {
OAuthToken.setToken({ token_type: 'bearer', access_token: 'foo', expires_in: 3600, refresh_token: 'bar' });
Expand Down

0 comments on commit 36d10ce

Please sign in to comment.