-
-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
1 parent
1b59acc
commit c99c308
Showing
1 changed file
with
132 additions
and
155 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|
@@ -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 | ||
|
||
|
@@ -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` | ||
|
@@ -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'; | ||
|
@@ -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 |