diff --git a/docs/media/authentication_guide.md b/docs/media/authentication_guide.md
index b327584723f..4659d733c92 100644
--- a/docs/media/authentication_guide.md
+++ b/docs/media/authentication_guide.md
@@ -292,7 +292,7 @@ this._validAuthStates = ['signedIn'];
in the component's constructor, then implement `showComponent(theme) {}` in lieu of the typical
`render() {}` method.
-### Federated Identities (Social Sign-in)
+### Using Federated Identities (Social Sign-in)
**Availibility Note**
Currently, our federated identity components only support Google, Facebook and Amazon identities, and works with React.
@@ -352,6 +352,125 @@ const federated = {
There is also `withGoogle`, `withFacebook`, `withAmazon` components, in case you need to customize a single provider.
+
+
+### Using Amazon Cognito Hosted UI
+
+Amazon Cognito provides a customizable user experience via the hosted UI. The hosted UI supports OAuth 2.0 and Federated Identities with Facebook, Amazon, Google, and SAML providers.
+
+Note: Amazon Cognito hosted UI feature is supported with *aws-amplify@^0.2.15* and *aws-amplify-react@^0.1.39* versions.
+{: .callout .callout--info}
+
+#### Setup your Cognito App Client
+
+To start using hosted UI, first, you need to setup your App Client in the Amazon Cognito console.
+
+To setup App Client;
+- Go to [Amazon Cognito Console](https://aws.amazon.com/cognito/).
+- Click *User Pools* on the top menu to select a User Pool or create a new one.
+- Click *App integration* and *App client settings* on the left menu.
+- Select *Enabled Identity Providers* and enter *Callback URL(s)* and *Sign out URL(s)* fields.
+- Under the *OAuth 2.0* section, select an OAuth Flow. *Authorization code grant* is the recommended choice for security reasons.
+- Choose item(s) from *OAuth Scopes*.
+- Click 'Save Changes'
+
+To enable the domain for your hosted UI;
+
+- On the left menu, go to *App integration* > *Domain name*.
+- In the *Domain prefix* section, enter the prefix for the pages that will be hosted by Amazon Cognito.
+
+You can also enable Federated Identities for your hosted UI;
+
+- Go to *Federation* > *Identity providers*
+- Select an *Identity provider* and enter required credentials for the identity provider. (e.g., App Id, App secret, Authorized scope)
+- In the settings page for your selected identity provider (Facebook, Google, etc.), set *Oauth Redirected URI* to `https://your-domain-prefix.auth.us-east 1.amazoncognito.com/oauth2/idpresponse` (*your-domain-prefix* is the domain prefix you have entered in previously).
+- To retrieve user attributes from your identity provider, go to *Federation* > *Attribute mapping*. Here, you can map Federation Provider attributes to corresponding User pool attributes.
+
+If *email* attribute is a required field in your Cognito User Pool settings, please make sure that you have selected *email* in your Authorized Scopes, and you have mapped it correctly to your User Pool attributes.
+{: .callout .callout-info}
+
+#### Configuring the Hosted UI
+
+To configure your application for hosted UI, you need to use *oauth* options:
+
+```js
+import Amplify from 'aws-amplify';
+
+const oauth = {
+ // Domain name
+ domain : 'your-domain-prefix.auth.us-east-1.amazoncognito.com',
+
+ // Authorized scopes
+ scope : ['phone', 'email', 'profile', 'openid','aws.cognito.signin.user.admin'],
+
+ // Callback URL
+ redirectSignIn : 'http://www.example.com/signin',
+
+ // Sign out URL
+ redirectSignOut : 'http://www.example.com/signout',
+
+ // 'code' for Authorization code grant,
+ // 'token' for Implicit grant
+ responseType: 'code'
+
+ // optional, for Cognito hosted ui specified options
+ options: {
+ // Indicates if the data collection is enabled to support Cognito advanced security features. By default, this flag is set to true.
+ AdvancedSecurityDataCollectionFlag : true
+ }
+}
+
+Amplify.configure({
+ Auth: {
+ // other configurations...
+ // ....
+ oauth: oauth
+ },
+ // ...
+});
+```
+
+#### Launching the Hosted UI
+
+To invoke the browser to display the hosted UI, you need to construct the URL in your app;
+
+```js
+const config = Auth.configure();
+const {
+ domain,
+ redirectSignIn,
+ redirectSignOut,
+ responseType } = config.oauth;
+
+const clientId = config.userPoolWebClientId;
+const url = 'https://' + domain + '/login?redirect_uri=' + redirectSignIn + '&response_type=' + responseType + '&client_id=' + clientId;
+
+// Launch hosted UI
+window.location.assign(url);
+
+```
+
+#### Launching the Hosted UI in React
+
+With React, you can simply use `withOAuth` HOC to launch the hosted UI experience. Just wrap your app's main component with our HOC:
+
+```js
+import { withOAuth } from 'aws-amplify-react';
+
+class MyApp extends React.Component {
+ // ...
+ render() {
+ return(
+
+ )
+ }
+}
+
+export default withOAuth(MyApp);
+```
+
### Enabling MFA (Multi-Factor Authentication)
Multi-factor authentication (MFA) increases security for your app by adding an authentication method and not relying solely on username (or alias) and password. AWS Amplify uses Amazon Cognito to provide MFA. Please see [Amazon Cognito Developer Guide](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-mfa.html) for more information about setting up MFA in Amazon Cognito.
diff --git a/packages/aws-amplify-react/__tests__/Auth/ConfirmSignIn-test.js b/packages/aws-amplify-react/__tests__/Auth/ConfirmSignIn-test.js
index 32c613a723f..844eeb66ea0 100644
--- a/packages/aws-amplify-react/__tests__/Auth/ConfirmSignIn-test.js
+++ b/packages/aws-amplify-react/__tests__/Auth/ConfirmSignIn-test.js
@@ -21,7 +21,7 @@ const deniedStates = [
];
describe('ConfirmSignIn', () => {
- describe('normal case', () => {
+ describe('render test', () => {
test('render correctly with Props confirmSignIn', () => {
const wrapper = shallow();
for (var i = 0; i < acceptedStates.length; i += 1){
@@ -33,6 +33,59 @@ describe('ConfirmSignIn', () => {
}
});
+ test('render corrently with other authstate', () => {
+ const wrapper = shallow();
+
+ for (var i = 0; i < deniedStates.length; i += 1){
+ wrapper.setProps({
+ authState: deniedStates[i],
+ theme: AmplifyTheme
+ });
+
+ expect(wrapper).toMatchSnapshot();
+ }
+ });
+
+ test('hidden if hide include confirmSignIn', () => {
+ const wrapper = shallow();
+ wrapper.setProps({
+ authState: acceptedStates[0],
+ hide: [ConfirmSignIn]
+ });
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ });
+
+ describe('confirm test', () => {
+ test('user with challengeName SOFTWARE_TOKEN_MFA', async () => {
+ const wrapper = shallow();
+
+ const spyon = jest.spyOn(Auth, 'confirmSignIn').mockImplementationOnce(() => {
+ return Promise.resolve();
+ });
+
+ wrapper.setProps({
+ authState: acceptedStates[0],
+ theme: AmplifyTheme,
+ authData: {
+ user: {
+ challengeName: 'SOFTWARE_TOKEN_MFA'
+ }
+ }
+ });
+
+ const confirmSignIn = wrapper.instance();
+
+ await confirmSignIn.confirm();
+
+ expect(spyon).toBeCalled();
+
+ spyon.mockClear();
+ });
+ });
+
+ describe('normal case', () => {
test('simulate clicking confirm button', async () => {
const spyon = jest.spyOn(Auth, 'confirmSignIn')
.mockImplementation((user, code) => {
@@ -83,19 +136,4 @@ describe('ConfirmSignIn', () => {
spyon2.mockClear();
});
});
-
- describe('null case with other authState', () => {
- test('render corrently', () => {
- const wrapper = shallow();
-
- for (var i = 0; i < deniedStates.length; i += 1){
- wrapper.setProps({
- authState: deniedStates[i],
- theme: AmplifyTheme
- });
-
- expect(wrapper).toMatchSnapshot();
- }
- });
- });
})
diff --git a/packages/aws-amplify-react/__tests__/Auth/FederatedSignIn-test.js b/packages/aws-amplify-react/__tests__/Auth/FederatedSignIn-test.js
index 35c38bd0a81..de50d98afb5 100644
--- a/packages/aws-amplify-react/__tests__/Auth/FederatedSignIn-test.js
+++ b/packages/aws-amplify-react/__tests__/Auth/FederatedSignIn-test.js
@@ -1,5 +1,12 @@
import React from 'react';
import FederatedSignIn, { FederatedButtons } from '../../src/Auth/FederatedSignIn';
+import { Auth } from 'aws-amplify';
+
+const spyon = jest.spyOn(Auth, 'configure').mockImplementation(() => {
+ return {
+ hostedUIOptions: {}
+ }
+})
describe('FederatedSignIn test', () => {
describe('render test', () => {
@@ -7,7 +14,7 @@ describe('FederatedSignIn test', () => {
const wrapper = shallow();
wrapper.setProps({
- federated: true,
+ federated: {},
authState: 'signIn',
onStateChange: jest.fn()
});
@@ -18,7 +25,7 @@ describe('FederatedSignIn test', () => {
const wrapper = shallow();
wrapper.setProps({
- federated: true,
+ federated: {},
authState: 'signedIn',
onStateChange: jest.fn()
});
@@ -29,7 +36,7 @@ describe('FederatedSignIn test', () => {
const wrapper = shallow();
wrapper.setProps({
- federated: false,
+ federated: undefined,
authState: 'signIn',
onStateChange: jest.fn()
});
diff --git a/packages/aws-amplify-react/__tests__/Auth/ForgotPassword-test.js b/packages/aws-amplify-react/__tests__/Auth/ForgotPassword-test.js
index 628b9d1b3ad..25870091efc 100644
--- a/packages/aws-amplify-react/__tests__/Auth/ForgotPassword-test.js
+++ b/packages/aws-amplify-react/__tests__/Auth/ForgotPassword-test.js
@@ -46,6 +46,15 @@ describe('forgotPassword', () => {
}
});
+ test('hidden if hide include ForgotPassword', () => {
+ const wrapper = shallow();
+ wrapper.setProps({
+ authState: acceptedStates[0],
+ hide: [ForgotPassword]
+ });
+ expect(wrapper).toMatchSnapshot();
+ });
+
test('simulating clicking submit', async () => {
const spyon = jest.spyOn(Auth, 'forgotPasswordSubmit')
.mockImplementationOnce(() => {
diff --git a/packages/aws-amplify-react/__tests__/Auth/Provider/__snapshots__/withOAuth-test.js.snap b/packages/aws-amplify-react/__tests__/Auth/Provider/__snapshots__/withOAuth-test.js.snap
new file mode 100644
index 00000000000..a9f530ef8e1
--- /dev/null
+++ b/packages/aws-amplify-react/__tests__/Auth/Provider/__snapshots__/withOAuth-test.js.snap
@@ -0,0 +1,13 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`withOAuth test render test render correctly 1`] = `
+
+`;
+
+exports[`withOAuth test render test render correctly with button 1`] = `
+
+`;
diff --git a/packages/aws-amplify-react/__tests__/Auth/Provider/withOAuth-test.js b/packages/aws-amplify-react/__tests__/Auth/Provider/withOAuth-test.js
new file mode 100644
index 00000000000..6b3f12fb385
--- /dev/null
+++ b/packages/aws-amplify-react/__tests__/Auth/Provider/withOAuth-test.js
@@ -0,0 +1,54 @@
+import React, { Component } from 'react';
+import withOAuth, { OAuthButton } from '../../../src/Auth/Provider/withOAuth';
+import { SignInButton, Button } from '../../../src/AmplifyUI';
+import { Auth } from 'aws-amplify';
+
+describe('withOAuth test', () => {
+ describe('render test', () => {
+ test('render correctly', () => {
+ const MockComp = class extends Component {
+ render() {
+ return
;
+ }
+ }
+
+ const Comp = withOAuth(MockComp);
+ const wrapper = shallow();
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ test('render correctly with button', () => {
+ const wrapper = shallow();
+ expect(wrapper).toMatchSnapshot();
+ });
+ });
+
+ describe('signIn test', () => {
+ test('happy case with connected response', () => {
+ const MockComp = class extends Component {
+ render() {
+ return ;
+ }
+ }
+
+ const spyon = jest.spyOn(Auth, 'configure').mockImplementation(() => {
+ return {
+ oauth: {
+ domain: 'domain',
+ redirectSignIn: 'redirectUriSignIn',
+ redirectSignOut: 'redirectUriSignOut',
+ responseType: 'responseType'
+ },
+ userPoolWebClientId: 'userPoolWebClientId'
+ }
+ })
+ const Comp = withOAuth(MockComp);
+ const wrapper = shallow();
+ const comp = wrapper.instance();
+
+ comp.signIn();
+
+ spyon.mockClear();
+ });
+ });
+});
\ No newline at end of file
diff --git a/packages/aws-amplify-react/__tests__/Auth/__snapshots__/ConfirmSignIn-test.js.snap b/packages/aws-amplify-react/__tests__/Auth/__snapshots__/ConfirmSignIn-test.js.snap
index ed451b7075c..b4a0244ea59 100644
--- a/packages/aws-amplify-react/__tests__/Auth/__snapshots__/ConfirmSignIn-test.js.snap
+++ b/packages/aws-amplify-react/__tests__/Auth/__snapshots__/ConfirmSignIn-test.js.snap
@@ -1,6 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`ConfirmSignIn normal case render correctly with Props confirmSignIn 1`] = `
+exports[`ConfirmSignIn render test hidden if hide include confirmSignIn 1`] = `""`;
+
+exports[`ConfirmSignIn render test render correctly with Props confirmSignIn 1`] = `
`;
-exports[`ConfirmSignIn null case with other authState render corrently 1`] = `""`;
+exports[`ConfirmSignIn render test render corrently with other authstate 1`] = `""`;
-exports[`ConfirmSignIn null case with other authState render corrently 2`] = `""`;
+exports[`ConfirmSignIn render test render corrently with other authstate 2`] = `""`;
-exports[`ConfirmSignIn null case with other authState render corrently 3`] = `""`;
+exports[`ConfirmSignIn render test render corrently with other authstate 3`] = `""`;
-exports[`ConfirmSignIn null case with other authState render corrently 4`] = `""`;
+exports[`ConfirmSignIn render test render corrently with other authstate 4`] = `""`;
-exports[`ConfirmSignIn null case with other authState render corrently 5`] = `""`;
+exports[`ConfirmSignIn render test render corrently with other authstate 5`] = `""`;
-exports[`ConfirmSignIn null case with other authState render corrently 6`] = `""`;
+exports[`ConfirmSignIn render test render corrently with other authstate 6`] = `""`;
-exports[`ConfirmSignIn null case with other authState render corrently 7`] = `""`;
+exports[`ConfirmSignIn render test render corrently with other authstate 7`] = `""`;
-exports[`ConfirmSignIn null case with other authState render corrently 8`] = `""`;
+exports[`ConfirmSignIn render test render corrently with other authstate 8`] = `""`;
diff --git a/packages/aws-amplify-react/__tests__/Auth/__snapshots__/FederatedSignIn-test.js.snap b/packages/aws-amplify-react/__tests__/Auth/__snapshots__/FederatedSignIn-test.js.snap
index 71be80c8a7a..5df1d56e740 100644
--- a/packages/aws-amplify-react/__tests__/Auth/__snapshots__/FederatedSignIn-test.js.snap
+++ b/packages/aws-amplify-react/__tests__/Auth/__snapshots__/FederatedSignIn-test.js.snap
@@ -753,7 +753,736 @@ exports[`FederatedButtons test render test render with correct authState and onl
exports[`FederatedSignIn test render test render nothing with incorrect authState 1`] = `""`;
-exports[`FederatedSignIn test render test render nothing with no federated prop 1`] = `""`;
+exports[`FederatedSignIn test render test render nothing with no federated prop 1`] = `
+
+
+
+
+
+`;
exports[`FederatedSignIn test render test render with correct authState 1`] = `
}
+ OAuth(oauth_config) {
+ if (!oauth_config) { return null;}
+ const { theme, onStateChange } = this.props;
+ return
+ }
+
render() {
const { authState } = this.props;
if (!['signIn', 'signedOut', 'signedUp'].includes(authState)) { return null; }
const federated = this.props.federated || {};
+ const config = Auth.configure();
+ if (config.oauth) {
+ federated.oauth_config = Object.assign({}, federated.oauth_config, config.oauth);
+ }
+
if (JS.isEmpty(federated)) { return null; }
- const { google_client_id, facebook_app_id, amazon_client_id } = federated;
+ const { google_client_id, facebook_app_id, amazon_client_id, oauth_config } = federated;
const theme = this.props.theme || AmplifyTheme;
return (
@@ -64,6 +80,7 @@ export class FederatedButtons extends Component {
{this.google(google_client_id)}
{this.facebook(facebook_app_id)}
{this.amazon(amazon_client_id)}
+ {this.OAuth(oauth_config)}
)
}
@@ -71,14 +88,20 @@ export class FederatedButtons extends Component {
export default class FederatedSignIn extends Component {
render() {
- const { federated, authState, onStateChange } = this.props;
+ const { authState, onStateChange } = this.props;
+ let federated = this.props.federated || {};
+ const config = Auth.configure();
+ if (config.oauth) {
+ federated.oauth_config = Object.assign({}, federated.oauth_config, config.oauth);
+ }
+
if (!federated) {
logger.debug('federated prop is empty. show nothing');
logger.debug('federated={google_client_id: , facebook_app_id: , amazon_client_id}');
return null;
}
if (!['signIn', 'signedOut', 'signedUp'].includes(authState)) { return null; }
-
+ logger.debug('federated Config is', federated);
const theme = this.props.theme || AmplifyTheme;
return (
diff --git a/packages/aws-amplify-react/src/Auth/Provider/index.jsx b/packages/aws-amplify-react/src/Auth/Provider/index.jsx
index c28cd5c5ae3..cc9a221dcd6 100644
--- a/packages/aws-amplify-react/src/Auth/Provider/index.jsx
+++ b/packages/aws-amplify-react/src/Auth/Provider/index.jsx
@@ -3,13 +3,15 @@ import React, { Component } from 'react';
import withGoogle from './withGoogle';
import withFacebook from './withFacebook';
import withAmazon from './withAmazon';
+import withOAuth from './withOAuth';
export { default as withGoogle, GoogleButton } from './withGoogle';
export { default as withFacebook, FacebookButton } from './withFacebook';
export { default as withAmazon, AmazonButton } from './withAmazon';
+export { default as withOAuth, OAuthButton } from './withOAuth';
export function withFederated(Comp) {
- const Federated = withAmazon(withGoogle(withFacebook(Comp)));
+ const Federated = withOAuth(withAmazon(withGoogle(withFacebook(Comp))));
return class extends Component {
render() {
diff --git a/packages/aws-amplify-react/src/Auth/Provider/withOAuth.jsx b/packages/aws-amplify-react/src/Auth/Provider/withOAuth.jsx
new file mode 100644
index 00000000000..ba9dee27038
--- /dev/null
+++ b/packages/aws-amplify-react/src/Auth/Provider/withOAuth.jsx
@@ -0,0 +1,52 @@
+import React, { Component } from 'react';
+
+import { Auth, Logger } from 'aws-amplify';
+import AmplifyTheme from '../../AmplifyTheme';
+import { SignInButton } from '../../AmplifyUI';
+
+const logger = new Logger('withOAuth');
+
+export default function withOAuth(Comp, options) {
+ return class extends Component {
+ constructor(props) {
+ super(props);
+ this.signIn = this.signIn.bind(this);
+ }
+
+ signIn() {
+ const config = this.props.oauth_config || options || Auth.configure().oauth;
+ logger.debug('withOAuth configuration', config);
+ const {
+ domain,
+ redirectSignIn,
+ redirectSignOut,
+ responseType
+ } = config;
+
+ const options = config.options || {};
+ const url = 'https://' + domain
+ + '/login?redirect_uri=' + redirectSignIn
+ + '&response_type=' + responseType
+ + '&client_id=' + (options.ClientId || Auth.configure().userPoolWebClientId);
+ window.location.assign(url);
+ }
+
+ render() {
+ return (
+
+ )
+ }
+ }
+}
+
+const Button = (props) => (
+
+ {props.label || 'Sign in with AWS'}
+
+)
+
+export const OAuthButton = withOAuth(Button);
\ No newline at end of file
diff --git a/packages/aws-amplify/__tests__/Analytics/Analytics-unit-test.ts b/packages/aws-amplify/__tests__/Analytics/Analytics-unit-test.ts
index 505274296c9..c28a3cb530b 100644
--- a/packages/aws-amplify/__tests__/Analytics/Analytics-unit-test.ts
+++ b/packages/aws-amplify/__tests__/Analytics/Analytics-unit-test.ts
@@ -93,7 +93,7 @@ describe("Analytics test", () => {
});
const spyon3 = jest.spyOn(AWSAnalyticsProvider.prototype, 'configure').mockImplementationOnce(() => { return; });
- expect(analytics.configure({attr: 'attr'})).toEqual({appId: 'appId', clientInfo: 'clientInfo'});
+ expect(analytics.configure({attr: 'attr'})).toEqual({appId: 'appId', clientInfo: 'clientInfo', attr: 'attr'});
spyon.mockClear();
spyon2.mockClear();
diff --git a/packages/aws-amplify/__tests__/Auth/auth-unit-test-rn.ts b/packages/aws-amplify/__tests__/Auth/auth-unit-test-rn.ts
index ab671402c75..2f88a6c8f97 100644
--- a/packages/aws-amplify/__tests__/Auth/auth-unit-test-rn.ts
+++ b/packages/aws-amplify/__tests__/Auth/auth-unit-test-rn.ts
@@ -148,23 +148,27 @@ import Cache from '../../src/Cache';
import { CognitoUserPool, CognitoUser, CognitoUserSession, CognitoIdToken, CognitoAccessToken } from 'amazon-cognito-identity-js';
import { CognitoIdentityCredentials } from 'aws-sdk';
-const authOptions: AuthOptions = {
- userPoolId: "awsUserPoolsId",
- userPoolWebClientId: "awsUserPoolsWebClientId",
- region: "region",
- identityPoolId: "awsCognitoIdentityPoolId"
+const authOptions = {
+ Auth: {
+ userPoolId: "awsUserPoolsId",
+ userPoolWebClientId: "awsUserPoolsWebClientId",
+ region: "region",
+ identityPoolId: "awsCognitoIdentityPoolId"
+ }
}
const authOptionsWithNoUserPoolId = {
- userPoolId: null,
- userPoolWebClientId: "awsUserPoolsWebClientId",
- region: "region",
- identityPoolId: "awsCognitoIdentityPoolId"
+ Auth: {
+ userPoolId: null,
+ userPoolWebClientId: "awsUserPoolsWebClientId",
+ region: "region",
+ identityPoolId: "awsCognitoIdentityPoolId"
+ }
}
const userPool = new CognitoUserPool({
- UserPoolId: authOptions.userPoolId,
- ClientId: authOptions.userPoolWebClientId
+ UserPoolId: authOptions.Auth.userPoolId,
+ ClientId: authOptions.Auth.userPoolWebClientId
});
const idToken = new CognitoIdToken({IdToken: 'idToken'});
diff --git a/packages/aws-amplify/__tests__/Auth/auth-unit-test.ts b/packages/aws-amplify/__tests__/Auth/auth-unit-test.ts
index 05514519641..9d57f785da7 100644
--- a/packages/aws-amplify/__tests__/Auth/auth-unit-test.ts
+++ b/packages/aws-amplify/__tests__/Auth/auth-unit-test.ts
@@ -27,6 +27,14 @@ jest.mock('amazon-cognito-identity-js/lib/CognitoUserSession', () => {
}
}
+ CognitoUserSession.prototype.isValid = () => {
+ return true;
+ }
+
+ CognitoUserSession.prototype.getRefreshToken = () => {
+ return 'refreshToken';
+ }
+
return CognitoUserSession;
});
@@ -126,13 +134,28 @@ jest.mock('amazon-cognito-identity-js/lib/CognitoUser', () => {
callback.onSuccess('session');
}
- CognitoUser.prototype.updateAttributes = (attributeList, callback) {
+ CognitoUser.prototype.updateAttributes = (attributeList, callback) => {
callback(null, 'SUCCESS');
}
+ CognitoUser.prototype.refreshSession = (refreshToken, callback) => {
+ callback(null, 'session');
+ }
+
return CognitoUser;
});
+jest.mock('amazon-cognito-auth-js/lib/CognitoAuth', () => {
+ const CognitoAuth = () => {};
+
+ CognitoAuth.prototype.parseCognitoWebResponse = () => {
+ CognitoAuth.prototype.userhandler.onSuccess();
+ throw 'err';
+ }
+
+ return CognitoAuth;
+});
+
jest.mock('../../src/Common/Builder', () => {
return {
default: null
@@ -144,24 +167,29 @@ import Auth from '../../src/Auth/Auth';
import Cache from '../../src/Cache';
import { CookieStorage, CognitoUserPool, CognitoUser, CognitoUserSession, CognitoIdToken, CognitoAccessToken } from 'amazon-cognito-identity-js';
import { CognitoIdentityCredentials, Credentials } from 'aws-sdk';
-
-const authOptions: AuthOptions = {
- userPoolId: "awsUserPoolsId",
- userPoolWebClientId: "awsUserPoolsWebClientId",
- region: "region",
- identityPoolId: "awsCognitoIdentityPoolId"
+import GoogleOAuth from '../../src/Common/OAuthHelper/GoogleOAuth';
+
+const authOptions = {
+ Auth: {
+ userPoolId: "awsUserPoolsId",
+ userPoolWebClientId: "awsUserPoolsWebClientId",
+ region: "region",
+ identityPoolId: "awsCognitoIdentityPoolId"
+ }
}
const authOptionsWithNoUserPoolId = {
- userPoolId: null,
- userPoolWebClientId: "awsUserPoolsWebClientId",
- region: "region",
- identityPoolId: "awsCognitoIdentityPoolId"
+ Auth: {
+ userPoolId: null,
+ userPoolWebClientId: "awsUserPoolsWebClientId",
+ region: "region",
+ identityPoolId: "awsCognitoIdentityPoolId"
+ }
}
const userPool = new CognitoUserPool({
- UserPoolId: authOptions.userPoolId,
- ClientId: authOptions.userPoolWebClientId
+ UserPoolId: authOptions.Auth.userPoolId,
+ ClientId: authOptions.Auth.userPoolWebClientId
});
const idToken = new CognitoIdToken({IdToken: 'idToken'});
@@ -487,6 +515,78 @@ describe('auth unit test', () => {
spyon.mockClear();
});
+ test('mfaSetup', async () => {
+ const spyon = jest.spyOn(CognitoUser.prototype, "authenticateUser")
+ .mockImplementationOnce((authenticationDetails, callback) => {
+ callback.mfaSetup('challengeName', 'challengeParam');
+ });
+ const auth = new Auth(authOptions);
+ const user = new CognitoUser({
+ Username: 'username',
+ Pool: userPool
+ });
+ const userAfterSignedIn = Object.assign(
+ {},
+ user,
+ {
+ "challengeName": "challengeName",
+ "challengeParam": "challengeParam"
+ });
+
+ expect.assertions(1);
+ expect(await auth.signIn('username', 'password')).toEqual(userAfterSignedIn);
+
+ spyon.mockClear();
+ });
+
+ test('totpRequired', async () => {
+ const spyon = jest.spyOn(CognitoUser.prototype, "authenticateUser")
+ .mockImplementationOnce((authenticationDetails, callback) => {
+ callback.totpRequired('challengeName', 'challengeParam');
+ });
+ const auth = new Auth(authOptions);
+ const user = new CognitoUser({
+ Username: 'username',
+ Pool: userPool
+ });
+ const userAfterSignedIn = Object.assign(
+ {},
+ user,
+ {
+ "challengeName": "challengeName",
+ "challengeParam": "challengeParam"
+ });
+
+ expect.assertions(1);
+ expect(await auth.signIn('username', 'password')).toEqual(userAfterSignedIn);
+
+ spyon.mockClear();
+ });
+
+ test('selectMFAType', async () => {
+ const spyon = jest.spyOn(CognitoUser.prototype, "authenticateUser")
+ .mockImplementationOnce((authenticationDetails, callback) => {
+ callback.selectMFAType('challengeName', 'challengeParam');
+ });
+ const auth = new Auth(authOptions);
+ const user = new CognitoUser({
+ Username: 'username',
+ Pool: userPool
+ });
+ const userAfterSignedIn = Object.assign(
+ {},
+ user,
+ {
+ "challengeName": "challengeName",
+ "challengeParam": "challengeParam"
+ });
+
+ expect.assertions(1);
+ expect(await auth.signIn('username', 'password')).toEqual(userAfterSignedIn);
+
+ spyon.mockClear();
+ });
+
test('newPasswordRequired', async () => {
const spyon = jest.spyOn(CognitoUser.prototype, "authenticateUser")
.mockImplementationOnce((authenticationDetails, callback) => {
@@ -758,10 +858,16 @@ describe('auth unit test', () => {
return user;
});
+ const spyon2 = jest.spyOn(Auth.prototype, 'userSession').mockImplementationOnce(() => {
+ return new Promise((res, rej) => {
+ res(session);
+ })
+ });
expect.assertions(1);
- expect(await auth.currentSession()).toBe('session');
+ expect(await auth.currentSession()).toEqual(session);
spyon.mockClear();
+ spyon2.mockClear();
});
test('callback failure', async () => {
@@ -807,12 +913,7 @@ describe('auth unit test', () => {
Pool: userPool
});
- const spyon = jest.spyOn(CognitoUser.prototype, "getSession");
- const spyon2 = jest.spyOn(CognitoUserPool.prototype, "getCurrentUser")
- .mockImplementationOnce(() => {
- return user;
- });
- const spyon3 = jest.spyOn(Auth.prototype, 'currentUserPoolUser')
+ const spyon = jest.spyOn(Auth.prototype, 'currentUserPoolUser')
.mockImplementationOnce(() => {
return new Promise((res, rej) => {
res(user);
@@ -823,7 +924,7 @@ describe('auth unit test', () => {
expect(await auth.currentAuthenticatedUser()).toEqual(user);
spyon.mockClear();
- spyon2.mockClear();
+
});
test('happy case with source federation', async () => {
@@ -845,7 +946,9 @@ describe('auth unit test', () => {
describe('userSession test', () => {
test('happy case', async () => {
- const spyon = jest.spyOn(CognitoUser.prototype, "getSession");
+ const spyon = jest.spyOn(CognitoUser.prototype, 'getSession').mockImplementationOnce((callback) => {
+ callback(null, session);
+ });
const auth = new Auth(authOptions);
const user = new CognitoUser({
@@ -854,11 +957,69 @@ describe('auth unit test', () => {
});
expect.assertions(1);
- expect(await auth.userSession(user)).toBe('session');
+ expect(await auth.userSession(user)).toEqual(session);
spyon.mockClear();
});
+ test('CognitoSession not valid and refresh successfully', async () => {
+ const spyon = jest.spyOn(CognitoUser.prototype, 'getSession').mockImplementationOnce((callback) => {
+ callback(null, session);
+ });
+
+ const spyon2 = jest.spyOn(CognitoUserSession.prototype, 'isValid').mockImplementationOnce(() => {
+ return false;
+ });
+
+ const spyon3 = jest.spyOn(CognitoUser.prototype, 'refreshSession').mockImplementationOnce((refreshToken, callback) => {
+ callback(null, session);
+ });
+
+ const auth = new Auth(authOptions);
+ const user = new CognitoUser({
+ Username: 'username',
+ Pool: userPool
+ });
+
+ expect.assertions(1);
+ expect(await auth.userSession(user)).toEqual(session);
+
+ spyon.mockClear();
+ spyon2.mockClear();
+ spyon3.mockClear();
+ });
+
+ test('CognitoSession not valid and refresh fails', async () => {
+ const spyon = jest.spyOn(CognitoUser.prototype, 'getSession').mockImplementationOnce((callback) => {
+ callback(null, session);
+ });
+
+ const spyon2 = jest.spyOn(CognitoUserSession.prototype, 'isValid').mockImplementationOnce(() => {
+ return false;
+ });
+
+ const spyon3 = jest.spyOn(CognitoUser.prototype, 'refreshSession').mockImplementationOnce((refreshToken, callback) => {
+ callback('err', null);
+ });
+
+ const auth = new Auth(authOptions);
+ const user = new CognitoUser({
+ Username: 'username',
+ Pool: userPool
+ });
+
+ expect.assertions(1);
+ try {
+ await auth.userSession(user);
+ } catch (e) {
+ expect(e).not.toBeNull();
+ }
+
+ spyon.mockClear();
+ spyon2.mockClear();
+ spyon3.mockClear();
+ });
+
test('callback error', async () => {
const auth = new Auth(authOptions);
const user = new CognitoUser({
@@ -883,15 +1044,14 @@ describe('auth unit test', () => {
});
describe('currentUserCredentials test', () => {
- test('with federated info', async () => {
+ test('with federated info and not expired', async () => {
const auth = new Auth(authOptions);
const spyon = jest.spyOn(Cache, 'getItem')
.mockImplementationOnce(() => {
return {
provider: 'google',
- token: 'token',
- user: {name: 'user'}
+ token: 'token'
}
});
@@ -900,6 +1060,84 @@ describe('auth unit test', () => {
spyon.mockClear();
});
+
+ test('with federated info and expired, then refresh it successfully', async () => {
+ const auth = new Auth(authOptions);
+
+ const spyon = jest.spyOn(Cache, 'getItem')
+ .mockImplementationOnce(() => {
+ return {
+ provider: 'google',
+ token: 'token',
+ expires_at: 0
+ }
+ });
+
+ auth._refreshHandlers = {
+ google: () => {
+ return Promise.resolve({
+ token: 'new_token',
+ expires_at: 1
+ });
+ }
+ }
+ expect.assertions(1);
+ expect(await auth.currentUserCredentials()).not.toBeUndefined();
+
+ spyon.mockClear();
+ });
+
+ test('with federated info and expired, no refresh handler provided', async () => {
+ const auth = new Auth(authOptions);
+
+ const spyon = jest.spyOn(Cache, 'getItem')
+ .mockImplementationOnce(() => {
+ return {
+ provider: 'google',
+ token: 'token',
+ expires_at: 0
+ }
+ });
+
+ auth._refreshHandlers = null;
+ expect.assertions(1);
+ try {
+ await auth.currentUserCredentials();
+ } catch (e) {
+ expect(e).not.toBeNull();
+ }
+
+ spyon.mockClear();
+ });
+
+ test('with federated info and expired, then refresh failed', async () => {
+ const auth = new Auth(authOptions);
+
+ const spyon = jest.spyOn(Cache, 'getItem')
+ .mockImplementationOnce(() => {
+ return {
+ provider: 'google',
+ token: 'token',
+ expires_at: 0
+ }
+ });
+
+ auth._refreshHandlers = {
+ google: () => {
+ return Promise.reject('err');
+ }
+ }
+ expect.assertions(1);
+ try {
+ await auth.currentUserCredentials();
+ } catch (e) {
+ expect(e).not.toBeNull();
+ }
+
+ spyon.mockClear();
+ });
+
+
});
describe('currentCrendentials', () => {
@@ -1205,8 +1443,16 @@ describe('auth unit test', () => {
const oldPassword = 'oldPassword1';
const newPassword = 'newPassword1.';
+ const spyon = jest.spyOn(Auth.prototype, 'userSession').mockImplementationOnce(() => {
+ return new Promise((res, rej) => {
+ res(session);
+ })
+ });
+
expect.assertions(1);
expect(await auth.changePassword(user, oldPassword, newPassword)).toBe('SUCCESS');
+
+ spyon.mockClear();
});
});
@@ -1457,7 +1703,7 @@ describe('auth unit test', () => {
expect.assertions(1);
- expect(await auth.currentUserInfo()).toEqual({});
+ expect(await auth.currentUserInfo()).toEqual(null);
});
test('no current userpool user', async () => {
@@ -1507,8 +1753,16 @@ describe('auth unit test', () => {
'phone_number': 'phone_number',
'sub': 'sub'
}
+ const spyon = jest.spyOn(Auth.prototype, 'userSession').mockImplementationOnce(() => {
+ return new Promise((res, rej) => {
+ res(session);
+ })
+ });
+
expect.assertions(1);
expect(await auth.updateUserAttributes(user,attributes)).toBe('SUCCESS');
+
+ spyon.mockClear();
});
});
@@ -1699,6 +1953,31 @@ describe('auth unit test', () => {
});
});
+ describe('hosted ui test', () => {
+ test('happy case', () => {
+ const oauth = {};
+
+ const authOptions = {
+ Auth: {
+ userPoolId: "awsUserPoolsId",
+ userPoolWebClientId: "awsUserPoolsWebClientId",
+ region: "region",
+ identityPoolId: "awsCognitoIdentityPoolId",
+ oauth
+ }
+ };
+ const spyon = jest.spyOn(Auth.prototype, 'currentAuthenticatedUser').mockImplementationOnce(() => {
+ return Promise.reject('err');
+ });
+
+
+ const auth = new Auth(authOptions);
+ expect(spyon).toBeCalled();
+
+ spyon.mockClear();
+
+ });
+ });
});
diff --git a/packages/aws-amplify/__tests__/Auth/totp-unit-test.ts b/packages/aws-amplify/__tests__/Auth/totp-unit-test.ts
index 56520959ce4..86c264c74c8 100644
--- a/packages/aws-amplify/__tests__/Auth/totp-unit-test.ts
+++ b/packages/aws-amplify/__tests__/Auth/totp-unit-test.ts
@@ -166,23 +166,28 @@ import Cache from '../../src/Cache';
import { CognitoUserPool, CognitoUser, CognitoUserSession, CognitoIdToken, CognitoAccessToken } from 'amazon-cognito-identity-js';
import { CognitoIdentityCredentials } from 'aws-sdk';
-const authOptions: AuthOptions = {
- userPoolId: "awsUserPoolsId",
- userPoolWebClientId: "awsUserPoolsWebClientId",
- region: "region",
- identityPoolId: "awsCognitoIdentityPoolId"
+
+const authOptions = {
+ Auth: {
+ userPoolId: "awsUserPoolsId",
+ userPoolWebClientId: "awsUserPoolsWebClientId",
+ region: "region",
+ identityPoolId: "awsCognitoIdentityPoolId"
+ }
}
const authOptionsWithNoUserPoolId = {
- userPoolId: null,
- userPoolWebClientId: "awsUserPoolsWebClientId",
- region: "region",
- identityPoolId: "awsCognitoIdentityPoolId"
+ Auth: {
+ userPoolId: null,
+ userPoolWebClientId: "awsUserPoolsWebClientId",
+ region: "region",
+ identityPoolId: "awsCognitoIdentityPoolId"
+ }
}
const userPool = new CognitoUserPool({
- UserPoolId: authOptions.userPoolId,
- ClientId: authOptions.userPoolWebClientId
+ UserPoolId: authOptions.Auth.userPoolId,
+ ClientId: authOptions.Auth.userPoolWebClientId
});
const idToken = new CognitoIdToken({IdToken: 'idToken'});
diff --git a/packages/aws-amplify/package.json b/packages/aws-amplify/package.json
index 0f914fe8afa..726405631a1 100644
--- a/packages/aws-amplify/package.json
+++ b/packages/aws-amplify/package.json
@@ -58,6 +58,7 @@
"webpack": "^3.5.5"
},
"dependencies": {
+ "amazon-cognito-auth-js": "^1.1.9",
"amazon-cognito-identity-js": "^2.0.0",
"aws-sdk": "2.198.0",
"axios": "^0.17.0",
diff --git a/packages/aws-amplify/src/Analytics/Analytics.ts b/packages/aws-amplify/src/Analytics/Analytics.ts
index 93ea26d11df..9b7166a7847 100644
--- a/packages/aws-amplify/src/Analytics/Analytics.ts
+++ b/packages/aws-amplify/src/Analytics/Analytics.ts
@@ -73,7 +73,7 @@ export default class AnalyticsClass {
public configure(config) {
logger.debug('configure Analytics');
const amplifyConfig = Parser.parseMobilehubConfig(config);
- const conf = Object.assign({}, this._config, amplifyConfig.Analytics);
+ const conf = Object.assign({}, this._config, amplifyConfig.Analytics, config);
const clientInfo:any = ClientDevice.clientInfo();
conf['clientInfo'] = conf['client_info']? conf['client_info'] : clientInfo;
diff --git a/packages/aws-amplify/src/Auth/Auth.ts b/packages/aws-amplify/src/Auth/Auth.ts
index 878e4a53d55..6819f90387a 100644
--- a/packages/aws-amplify/src/Auth/Auth.ts
+++ b/packages/aws-amplify/src/Auth/Auth.ts
@@ -16,12 +16,14 @@ import { AuthOptions, FederatedResponse } from './types';
import {
AWS,
Cognito,
+ CognitoHostedUI,
ConsoleLogger as Logger,
Constants,
Hub,
FacebookOAuth,
GoogleOAuth,
- JS
+ JS,
+ Parser
} from '../Common';
import Platform from '../Common/Platform';
import Cache from '../Cache';
@@ -34,6 +36,8 @@ const {
Credentials
} = AWS;
+const { CognitoAuth } = CognitoHostedUI;
+
const {
CookieStorage,
CognitoUserPool,
@@ -53,6 +57,7 @@ export default class AuthClass {
private _config: AuthOptions;
private _userPoolStorageSync: Promise;
private userPool = null;
+ private _cognitoAuthClient = null;
private credentials = null;
private credentials_source = ''; // aws, guest, userPool, federated
@@ -79,20 +84,13 @@ export default class AuthClass {
}
configure(config) {
+ if (!config) return this._config;
logger.debug('configure Auth');
- let conf = config? config.Auth || config : {};
- if (conf['aws_cognito_identity_pool_id']) {
- conf = {
- userPoolId: conf['aws_user_pools_id'],
- userPoolWebClientId: conf['aws_user_pools_web_client_id'],
- region: conf['aws_cognito_region'],
- identityPoolId: conf['aws_cognito_identity_pool_id'],
- mandatorySignIn: conf['aws_mandatory_sign_in'] === 'enable'? true: false
- };
- }
- this._config = Object.assign({}, this._config, conf);
+ const conf = Object.assign({}, this._config, Parser.parseMobilehubConfig(config).Auth, config);
+ this._config = conf;
+
if (!this._config.identityPoolId) { logger.debug('Do not have identityPoolId yet.'); }
- const { userPoolId, userPoolWebClientId, cookieStorage } = this._config;
+ const { userPoolId, userPoolWebClientId, cookieStorage, oauth } = this._config;
if (userPoolId) {
const userPoolData: ICognitoUserPoolData = {
UserPoolId: userPoolId,
@@ -115,6 +113,52 @@ export default class AuthClass {
});
}
}
+
+ // initiailize cognitoauth client if hosted ui options provided
+ if (oauth) {
+ const that = this;
+
+ const cognitoAuthParams = Object.assign(
+ {
+ ClientId: userPoolWebClientId,
+ UserPoolId: userPoolId,
+ AppWebDomain: oauth.domain,
+ TokenScopesArray: oauth.scope,
+ RedirectUriSignIn: oauth.redirectSignIn,
+ RedirectUriSignOut: oauth.redirectSignOut,
+ ResponseType: oauth.responseType
+ },
+ oauth.options
+ );
+
+ logger.debug('cognito auth params', cognitoAuthParams);
+ this._cognitoAuthClient = new CognitoAuth(cognitoAuthParams);
+ this._cognitoAuthClient.userhandler = {
+ // user signed in
+ onSuccess: (result) => {
+ that.user = that.userPool.getCurrentUser();
+ logger.debug("Cognito Hosted authentication result", result);
+ that.currentSession().then((session) => {
+ that._setCredentialsFromSession(session).then((cred) => {
+ logger.debug('sign in succefully with', cred);
+ dispatchAuthEvent('signIn', that.user);
+ });
+ });
+ },
+ onFailure: (err) => {
+ logger.debug("Error in cognito hosted auth response", err);
+ }
+ };
+ // if not logged in, try to parse the url.
+ this.currentAuthenticatedUser().then(() => {
+ logger.debug('user already logged in');
+ }).catch(e => {
+ logger.debug('not logged in, try to parse the url');
+ const curUrl = window.location.href;
+ this._cognitoAuthClient.parseCognitoWebResponse(curUrl);
+ });
+ }
+
dispatchAuthEvent('configured', null);
return this._config;
}
@@ -643,6 +687,7 @@ export default class AuthClass {
* @return - A promise resolves to curret authenticated CognitoUser if success
*/
public async currentAuthenticatedUser(): Promise {
+ logger.debug('getting current authenticted user');
let federatedUser = null;
try {
federatedUser = await Cache.getItem('federatedUser');
@@ -654,8 +699,7 @@ export default class AuthClass {
this.user = federatedUser;
logger.debug('get current authenticated federated user', this.user);
return this.user;
- }
- else {
+ } else {
logger.debug('get current authenticated userpool user');
try {
this.user = await this.currentUserPoolUser();
@@ -673,16 +717,22 @@ export default class AuthClass {
public currentSession() : Promise {
let user:any;
const that = this;
- logger.debug('getting current session');
+ logger.debug('Getting current session');
if (!this.userPool) { return Promise.reject('No userPool'); }
if (Platform.isReactNative) {
return this.getSyncedUser().then(user => {
- if (!user) { return Promise.reject('No current user'); }
+ if (!user) {
+ logger.debug('Failed to get user from user pool');
+ return Promise.reject('No current user');
+ }
return that.userSession(user);
});
} else {
user = this.userPool.getCurrentUser();
- if (!user) { return Promise.reject('No current user'); }
+ if (!user) {
+ logger.debug('Failed to get user from user pool');
+ return Promise.reject('No current user');
+ }
return this.userSession(user);
}
}
@@ -694,9 +744,30 @@ export default class AuthClass {
*/
public userSession(user) : Promise {
return new Promise((resolve, reject) => {
- logger.debug(user);
+ logger.debug('Getting the session from this user:', user);
user.getSession(function(err, session) {
- if (err) { reject(err); } else { resolve(session); }
+ if (err) {
+ logger.debug('Failed to get the session from user', user);
+ reject(err);
+ } else {
+ logger.debug('Succeed to get the user session', session);
+ // check if session is expired
+ if (!session.isValid()) {
+ const refreshToken = session.getRefreshToken();
+ logger.debug('Session is not valid, refreshing session with refreshToken', refreshToken);
+ user.refreshSession(refreshToken, (err, newSession) => {
+ if (err) {
+ logger.debug('Refresh Cognito Session failed', err);
+ reject(err);
+ }
+ logger.debug('Refresh Cognito Session success', newSession);
+ resolve(newSession);
+ });
+ } else {
+ logger.debug('Session is valid, directly return this session');
+ resolve(session);
+ }
+ }
});
});
}
@@ -707,7 +778,7 @@ export default class AuthClass {
*/
public currentUserCredentials() : Promise {
const that = this;
- logger.debug('getting current user credential');
+ logger.debug('Getting current user credentials');
if (Platform.isReactNative) {
// asyncstorage
return Cache.getItem('federatedInfo')
@@ -746,6 +817,7 @@ export default class AuthClass {
}
private _refreshFederatedToken(federatedInfo) {
+ logger.debug('Getting federated credentials');
const { provider, user } = federatedInfo;
let token = federatedInfo.token;
let expires_at = federatedInfo.expires_at;
@@ -779,6 +851,7 @@ export default class AuthClass {
}
public currentCredentials(): Promise {
+ logger.debug('getting current credntials');
return this.pickupCredentials();
}
@@ -847,9 +920,11 @@ export default class AuthClass {
if (source === 'aws' || source === 'userPool') {
if (!this.userPool) { return Promise.reject('No userPool'); }
const user = this.userPool.getCurrentUser();
- if (user) {
- logger.debug('user sign out', user);
- user.signOut();
+ if (!user) { return Promise.resolve(); }
+ logger.debug('user sign out', user);
+ user.signOut();
+ if (this._cognitoAuthClient) {
+ this._cognitoAuthClient.signOut();
}
}
@@ -1013,9 +1088,6 @@ export default class AuthClass {
*/
public federatedSignIn(provider: string, response: FederatedResponse, user: object) {
const { token, expires_at } = response;
-
- // store it into localstorage
- // Cache.setItem('federatedInfo', { provider, token, user, expires_at }, { priority: 1 });
const that = this;
return new Promise((res, rej) => {
that._setCredentialsFromFederation({ provider, token, user, expires_at }).then((cred) => {
@@ -1025,7 +1097,7 @@ export default class AuthClass {
}).catch(e => {
rej(e);
});
- });
+ });
}
/**
@@ -1185,12 +1257,14 @@ export default class AuthClass {
}
private keepAlive() {
+ logger.debug('checking if credentials exists and not expired');
const cred = this.credentials;
if (cred && !this._isExpired(cred)) {
- logger.debug('not changed, directly return credentials');
+ logger.debug('credentials not changed and not expired, directly return');
return Promise.resolve(cred);
}
+ logger.debug('need to get a new credential or refresh the existing one');
return this.currentUserCredentials();
}
diff --git a/packages/aws-amplify/src/Auth/types/Auth.ts b/packages/aws-amplify/src/Auth/types/Auth.ts
index dedbeb21fc3..33cd0809432 100644
--- a/packages/aws-amplify/src/Auth/types/Auth.ts
+++ b/packages/aws-amplify/src/Auth/types/Auth.ts
@@ -32,6 +32,7 @@ export interface AuthOptions {
region?: string,
mandatorySignIn: boolean
cookieStorage?: ICookieStorageData,
+ oauth?: OAuth
}
/**
@@ -51,3 +52,12 @@ export interface FederatedResponse {
// the universal time when token expired
expires_at: number
}
+
+export interface OAuth {
+ domain : string,
+ scope : Array,
+ redirectSignIn : string,
+ redirectSignOut : string,
+ responseType: string,
+ options?: object
+}
diff --git a/packages/aws-amplify/src/Common/Facet.ts b/packages/aws-amplify/src/Common/Facet.ts
index 6d6e247480c..b7359088f4a 100644
--- a/packages/aws-amplify/src/Common/Facet.ts
+++ b/packages/aws-amplify/src/Common/Facet.ts
@@ -17,5 +17,6 @@ import * as AWS from 'aws-sdk/global';
import * as Cognito from 'amazon-cognito-identity-js';
import * as Pinpoint from 'aws-sdk/clients/pinpoint';
import * as MobileAnalytics from 'aws-sdk/clients/mobileanalytics';
+import * as CognitoHostedUI from 'amazon-cognito-auth-js';
-export {AWS, S3, Cognito, Pinpoint, MobileAnalytics };
+export {AWS, S3, Cognito, Pinpoint, MobileAnalytics, CognitoHostedUI };
diff --git a/packages/aws-amplify/src/Common/Parser.ts b/packages/aws-amplify/src/Common/Parser.ts
index eaec3815024..2440cf32538 100644
--- a/packages/aws-amplify/src/Common/Parser.ts
+++ b/packages/aws-amplify/src/Common/Parser.ts
@@ -1,17 +1,35 @@
import { AmplifyConfig } from './types';
+import { ConsoleLogger as Logger } from '../Common';
+
+const logger = new Logger('Parser');
export default class Parser {
static parseMobilehubConfig(config): AmplifyConfig {
const amplifyConfig: AmplifyConfig = {};
// Analytics
if (config['aws_mobile_analytics_app_id']) {
- const Analytics = {};
- Analytics['appId'] = config['aws_mobile_analytics_app_id'];
- Analytics['region'] = config['aws_mobile_analytics_app_region'];
+ const Analytics = {
+ appId: config['aws_mobile_analytics_app_id'],
+ region: config['aws_mobile_analytics_app_region']
+ };
amplifyConfig.Analytics = Analytics;
}
+ // Auth
+ if (config['aws_cognito_identity_pool_id']) {
+ const Auth = {
+ userPoolId: config['aws_user_pools_id'],
+ userPoolWebClientId: config['aws_user_pools_web_client_id'],
+ region: config['aws_cognito_region'],
+ identityPoolId: config['aws_cognito_identity_pool_id'],
+ mandatorySignIn: config['aws_mandatory_sign_in'] === 'enable'? true: false
+ };
+ amplifyConfig.Auth = Auth;
+ }
+
amplifyConfig.Analytics = Object.assign({}, amplifyConfig.Analytics, config.Analytics);
+ amplifyConfig.Auth = Object.assign({}, amplifyConfig.Auth, config.Auth);
+ logger.debug('parse config', config, 'to amplifyconfig', amplifyConfig);
return amplifyConfig;
}
}
diff --git a/yarn.lock b/yarn.lock
index 7a6ec2e18fa..1cee70c70a5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -193,6 +193,10 @@ align-text@^0.1.1, align-text@^0.1.3:
longest "^1.0.1"
repeat-string "^1.5.2"
+amazon-cognito-auth-js@^1.1.9:
+ version "1.1.9"
+ resolved "https://registry.yarnpkg.com/amazon-cognito-auth-js/-/amazon-cognito-auth-js-1.1.9.tgz#f230508aac15bf06da152a39fc426d063a72cfa6"
+
amdefine@>=0.0.4:
version "1.0.1"
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
@@ -432,6 +436,17 @@ awesome-typescript-loader@^3.2.2:
object-assign "^4.1.1"
source-map-support "^0.4.15"
+aws-amplify@^0.2.14, aws-amplify@^0.2.x:
+ version "0.2.15"
+ resolved "https://registry.yarnpkg.com/aws-amplify/-/aws-amplify-0.2.15.tgz#8ea5364e4082ebbd845aa8a4544dc760639b45ca"
+ dependencies:
+ amazon-cognito-identity-js "^2.0.0"
+ aws-sdk "2.198.0"
+ axios "^0.17.0"
+ paho-mqtt "^1.0.4"
+ uuid "^3.2.1"
+ zen-observable "^0.8.6"
+
aws-sdk@2.198.0:
version "2.198.0"
resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.198.0.tgz#2245311337ddc844cc34c13f3fcf3b7ea843f434"