Skip to content

Commit

Permalink
Update README
Browse files Browse the repository at this point in the history
Updates the Readme for the new Amplify API, and removes the
deprecated ember-qunit < 4.2 helpers. It also removes much of the
CognitoUser documentation, since Amplify's API has promises already.
  • Loading branch information
paulcwatts committed Jun 10, 2019
1 parent 1b59acc commit c99c308
Showing 1 changed file with 132 additions and 155 deletions.
287 changes: 132 additions & 155 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# ember-cognito
## An authenticator and library for using ember-simple-auth and Amazon Cognito
## An authenticator and library for using ember-simple-auth and AWS Amplify/Cognito

[![Build Status](https://travis-ci.org/paulcwatts/ember-cognito.svg?branch=master)](https://travis-ci.org/paulcwatts/ember-cognito)
[![Code Climate](https://codeclimate.com/github/paulcwatts/ember-cognito/badges/gpa.svg)](https://codeclimate.com/github/paulcwatts/ember-cognito)
Expand All @@ -8,15 +8,18 @@
[![npm version](https://badge.fury.io/js/ember-cognito.svg)](https://badge.fury.io/js/ember-cognito)
[![Greenkeeper badge](https://badges.greenkeeper.io/paulcwatts/ember-cognito.svg)](https://greenkeeper.io/)

Ember Cognito is an Ember Addon that integrates [ember-simple-auth](https://github.com/simplabs/ember-simple-auth/)
with [Amazon Cognito](https://aws.amazon.com/cognito/) User Pools.
Ember Cognito is an Ember Addon that integrates
[ember-simple-auth](https://github.com/simplabs/ember-simple-auth/)
with [AWS Amplify](https://aws-amplify.github.io/docs/) and
[AWS Cognito](https://aws.amazon.com/cognito/) User Pools.

ember-simple-auth is a lightweight library for implementing authentication/authorization in Ember.js.
Amazon Cognito is a managed authentication system for mobile and web apps on Amazon Web Services.
ember-simple-auth is a lightweight library for implementing authentication/authorization
in Ember.js. AWS Amplify is a client framework, developed by Amazon, which uses Amazon
Cognito as a managed authentication system for mobile and web apps on Amazon Web Services.

ember-cognito implements an ember-simple-auth custom authenticator that can be used to authenticate with
a Cognito User Pool. It also provides some helper classes that convert Cognito's callback-oriented API to
a promise-oriented API.
ember-cognito implements an ember-simple-auth custom authenticator that can be used
in an AWS Amplify application, or any Ember application, to authenticate with
a Cognito User Pool.

## Installation

Expand All @@ -38,15 +41,17 @@ var ENV = {
};
```

Note that the Cognito JavaScript SDK requires that your App be created *without* a Client Secret.
Note that the Cognito JavaScript SDK requires that your App be created *without* a
Client Secret.

## Optional Configuration

You can specify these optional configuration options to the above configuration hash:

* `autoRefreshSession`. Cognito access tokens are only valid for an hour. By default, this addon will
refresh expired sessions on application startup. Setting `autoRefreshSession` to `true` will enable a timer
that will automatically refresh the Cognito session when it expires.
* `autoRefreshSession`. Cognito access tokens are only valid for an hour. By default,
this addon will refresh expired sessions on application startup.
Setting `autoRefreshSession` to `true` will enable a timer that will automatically
refresh the Cognito session when it expires.

* `authenticationFlowType`. The authentication flow type that should be used.
Default value: `USER_SRP_AUTH`
Expand All @@ -57,189 +62,127 @@ More details - [Auth Flow](https://docs.aws.amazon.com/cognito-user-identity-poo

### Cognito Authenticator

The Cognito Authenticator authenticates an ember-simple-auth session with Amazon Cognito. It overwrites
the Amazon SDK's storage mechanism (which is hardcoded to use localStorage) to instead store the authentication
data in ember-simple-auth's session-store. This makes it easier to integrate Cognito in Ember unit tests.

You will call the authenticator just as you would a normal authenticator:
The Cognito Authenticator authenticates an ember-simple-auth session with
Amplify/Cognito:

```js
import Controller from '@ember/controller';
import Component from '@ember/component';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';

export default Controller.extend({
session: service('session'),

actions: {
authenticate() {
let { username, password } = this.getProperties('username', 'password');
let credentials = {
username: username,
password: password
};
this.get('session').authenticate('authenticator:cognito', credentials).then((cognitoUserSession) => {
// Successfully authenticated!
}).catch((error) => {
this.set('errorMessage', error.message || error);
});
export default class LoginComponent extends Component {
@service session;

@action
async authenticate() {
const { username, password } = this;
const credentials = { username, password };
try {
await this.session.authenticate('authenticator:cognito', credentials);
} catch (error) {
this.set('errorMessage', error.message || error);
}
}
});
}
```

### Integrating with an Authorizer
#### Integrating with an Ember Data Adapter

The Cognito Authenticator will put the Cognito ID token in the `access_token` property in the session's
`authenticated` data. This means integrating with an Authorizer such as the OAuth2 Bearer requires no
special configuration.
`authenticated` data. This means integrating with ember-simple-auth's
[Ember Data Adapter Mixin](https://github.com/simplabs/ember-simple-auth/blob/master/addon/mixins/data-adapter-mixin.js)
requires no special configuration.

### Cognito SDK Vendor Shim

ember-cognito provides a vendor shim that allows you to import [Cognito Identity SDK's](https://github.com/aws/amazon-cognito-identity-js/)
classes using ES modules:
### Cognito Service

```js
import { CognitoUserPool, CognitoUserAttribute, CognitoUser } from 'amazon-cognito-identity-js';
```
The addon provides a `cognito` service that provides some helpers to access the
Amplify auth object. The service provides access to the following Amplify/auth methods:

### CognitoUser
* `signUp(username, password, attributes, validationData)`
* `confirmSignUp(username, code, options)`
* `resendSignUp(username)`
* `forgotPassword(username)`
* `forgotpasswordSubmit(username, code, newPassword)`

[CognitoUser](https://github.com/paulcwatts/ember-cognito/blob/master/addon/utils/cognito-user.js) is a helper
Ember object that provides promisified versions of the Cognito Identity SDK's callback methods.
For instance, you can take this code from the Cognito SDK:
It also provides a helper to quickly access the current user's Cognito ID token:

```js
import { CognitoUser } from 'amazon-cognito-identity-js';
* `getIdToken()`

cognitoUser.getUserAttributes(function(err, result) {
if (err) {
alert(err);
return;
}
for (let i = 0; i < result.length; i++) {
console.log('attribute ' + result[i].getName() + ' has value ' + result[i].getValue());
}
});
```
#### Cognito User

And rewrite it to use Promises and other ES2015 goodness:
The Cognito service allows you to access the currently authenticated `CognitoUser`
object, along with the following helper methods:

```js
import { CognitoUser } from 'ember-cognito/utils/cognito-user';
* `changePassword(oldPassword, newPassword)`
* `deleteAttributes(attributeList)`
* `deleteUser()`
* `getSession()`
* `getUserAttributes()`
* `getUserAttributesHash()`
* `signOut()`
* `updateAttributes()`
* `verifyAttribute()`
* `getGroups()`

cognitoUser.getUserAttributes().then((userAttributes) => {
userAttributes.forEach((attr) => {
console.log(`attribute ${attr.getName()} has value ${attr.getValue()}`);
});
}).catch((err) => {
alert(err);
});
```

### CognitoService

The Cognito service allows you to access the currently authenticated `CognitoUser` object.
For instance, if you use a `current-user` service using the
If you use a `current-user` service using the
[ember-simple-auth guide](https://github.com/simplabs/ember-simple-auth/blob/master/guides/managing-current-user.md),
you can use the Cognito Service to fetch user attributes:
you can use the Cognito User to fetch user attributes:

```js
import Service from '@ember/service';
import { inject as service } from '@ember/service';
import { readOnly } from '@ember/object/computed';
import { resolve } from 'rsvp';

export default Service.extend({
session: service(),
cognito: service(),
cognitoUser: readOnly('cognito.user'),
username: readOnly('cognitoUser.username'),

load() {
if (this.get('session.isAuthenticated')) {
return this.get('cognitoUser').getUserAttributes().then((userAttributes) => {
userAttributes.forEach((attr) => {
this.set(attr.getName(), attr.getValue());
});

export default class CurrentUserService extends Service {
@service session;
@service cognito;
@readOnly('cognito.user') cognitoUser;
@readOnly('cognitoUser.username') username;

async load() {
if (this.session.isAuthenticated) {
const userAttributes = await this.cognitoUser.getUserAttributes();
userAttributes.forEach((attr) => {
this.set(attr.getName(), attr.getValue());
});
} else {
return resolve();
}
}
});
}
```

See [the dummy app](https://github.com/paulcwatts/ember-cognito/blob/master/tests/dummy/app/services/current-user.js)
for an example of this in action.
You can see examples of usages of these API methods in the
[full-featured dummy app](https://github.com/paulcwatts/ember-cognito/blob/master/tests/dummy/app).


#### Advanced Configuration

If you don't want to specify the Pool ID and Client ID in the Ember environment, you can override the CognitoService
in your own app and provide the configuration there.
If you don't want to specify the Pool ID and Client ID in the Ember environment, you
can override the CognitoService in your own app and provide the configuration there.

```js
// app/services/cognito.js
import CognitoService from 'ember-cognito/services/cognito';
import BaseCognitoService from 'ember-cognito/services/cognito';

export default CognitoService.extend({
poolId: '<my pool ID>',
clientId: '<my client ID>'
});
export default class CognitoService extends BaseCognitoService {
poolId = '<my pool ID>';
clientId = '<my client ID>;
}
```
In this case, you can have the properties be computed or retrieved through some dynamic mechanism.
In this case, you can have the properties be computed or retrieved through some dynamic
mechanism.
## Testing
ember-cognito provides some helpers and utilities that make it easier to work with Cognito in tests.

### MockUser

`MockUser` can be used to mock `CognitoUser` so you don't make Cognito calls in tests.

```js
import { MockUser } from '<app>/tests/utils/ember-cognito';

let mockUser = MockUser.create({
username: 'testuser',
userAttributes: [
{ name: 'sub', value: 'aaaabbbb-cccc-dddd-eeee-ffffgggghhhh' },
{ name: 'first_name', value: 'Steve' }
]
});
```

This can be used in unit or integration tests where a `CognitoUser` is needed.
ember-cognito provides some helpers and utilities that make it easier to work with
Cognito in tests.
### mockCognitoUser
In acceptance tests, you can use ember-simple-auth's `authenticateSession` to create a user, but
you will may also need to mock the user on the Cognito service. You can do this using `mockCognitoUser`:

```js
import { authenticateSession } from '<app>/tests/helpers/ember-simple-auth';
import { mockCognitoUser } from '<app>/tests/helpers/ember-cognito';

test('authenticated route', function(assert) {
authenticateSession(this.application);
mockCognitoUser(this.application, {
username: 'testuser',
userAttributes: [
{ name: 'sub', value: 'aaaabbbb-cccc-dddd-eeee-ffffgggghhhh' },
{ name: 'email', value: '[email protected]' }
]
});
// ..
});
```

See [the dummy app](https://github.com/paulcwatts/ember-cognito/blob/master/tests/acceptance/index-test.js)
for an example of this type of test.

If your app is using `ember-cli-qunit` 4.2.0 or greater, consider migrating to the [modern testing syntax](https://dockyard.com/blog/2018/01/11/modern-ember-testing).
In this case, helpers can be imported from the `ember-cognito` namespace, and can be used
in any type of test (unit, integration, acceptance).

In acceptance tests, you can use ember-simple-auth's `authenticateSession` to create a
user, but you may also need to mock user attributes on the Cognito service. You can do
this using `mockCognitoUser`:

```js
import { authenticateSession } from 'ember-simple-auth/test-support';
Expand All @@ -252,15 +195,49 @@ module('Acceptance | authenticated route', function(hooks) {
username: 'testuser'
// userAttributes...
});
// No helper necessary to get the authenticator!
let authenticator = this.owner.lookup('authenticator:cognito');

const authenticator = this.owner.lookup('authenticator:cognito');
// Rest of the test
});
});
```

## Support
### mockAuth

In some cases, you may want to mock the Amplify auth object to test authentication
scenarios. You can use the `mockAuth` helper to add your own mock class to
stub certain Amplify functions in tests:

* Ember versions 2.18, 3.4 and 3.9+
* Amazon Cognito SDK 3.x.
```js
import { mockAuth, MockAuth } from 'ember-cognito/test-support';
module('Acceptance | login', function(hooks) {
setupApplicationTest(hooks);
test('login failure', async function(assert) {
await mockAuth(MockAuth.extend({
signIn() {
return reject({ message: 'Username or password incorrect.' });
}
}));
// Attempt to login,
await visit('/login');
await fillIn('#username', 'testuser');
await fillIn('#password', 'password');
await click('[type=submit]');
assert.dom('[data-test-error]').hasText('Username or password incorrect.');
});
});
```

## Dummy App

The [dummy app](https://github.com/paulcwatts/ember-cognito/blob/master/tests/dummy/app)
includes many use cases for you to see this addon in action, including new user sign up,
login, logout, and updating/verifying user attributes.

## Support

* Ember versions 2.18, 3.4 and 3.10+
* AWS Amplify 1.x

0 comments on commit c99c308

Please sign in to comment.