## OAuth and Federation Overview
[OAuth 2.0](https://en.wikipedia.org/wiki/OAuth) is the common Authorization framework used by web and mobile applications for getting access to user information ("scopes") in a limited manner. Common analogies you will hear in OAuth is that of boarding a plane or staying in a hotel - showing your identification is the Authentication piece (signing into an app) and using the boarding pass/hotel key is what you are Authorized to access.
OAuth support in Amplify uses Cognito User Pools and supports federation with social providers, which will automatically create a corresponding user in the User Pool after a login. [OIDC](https://en.wikipedia.org/wiki/OpenID_Connect) tokens are available in the app after the application has completed this process.
import all0 from "/src/fragments/lib/auth/common/social_signin_web_ui/setup_auth_provider.mdx";
## Configure Auth Category
Once you have the social provider configured, run the following in your project’s root folder:
```bash
amplify add auth ## "amplify update auth" if already configured
```
Choose the following options:
```console
? Do you want to use the default authentication and security configuration?
`Default configuration with Social Provider (Federation)`
? How do you want users to be able to sign in?
`Username`
? Do you want to configure advanced settings?
`No, I am done.`
? What domain name prefix you want us to create for you?
`(default)`
? Enter your redirect signin URI:
`myapp://`
? Do you want to add another redirect signin URI
`No`
? Enter your redirect signout URI:
`myapp://`
? Do you want to add another redirect signout URI
`No`
? Select the social providers you want to configure for your user pool:
``
```
You can configure you application to use more than one redirect URL. For more information, refer to the [Redirect URLs](#redirect-urls) section.
import all1 from "/src/fragments/lib/auth/common/social_signin_web_ui/configure_auth_category.mdx";
## Setup frontend
After configuring the OAuth endpoints (Cognito Hosted UI), you can integrate your App by invoking `Auth.federatedSignIn()` function. Passing `LoginWithAmazon`, `Facebook`, `Google`, or `SignInWithApple` on the `provider` argument (e.g `Auth.federatedSignIn({ provider: 'LoginWithAmazon' })`) will bypass the Hosted UI and federate immediately with the social provider as shown in the below React Native example. If you are looking to add a custom state, you are able to do so by passing a string (e.g. `Auth.federatedSignIn({ customState: 'xyz' })`) value and listening for the custom state via Hub.
```ts
import { useEffect, useState } from "react";
import { Text, View, Linking, Button } from "react-native";
import { CognitoHostedUIIdentityProvider } from "@aws-amplify/auth";
import { Amplify, Auth, Hub } from "aws-amplify";
import awsconfig from "./aws-exports";
Amplify.configure(awsconfig);
export default function App() {
const [user, setUser] = useState(null);
const [customState, setCustomState] = useState(null);
useEffect(() => {
const unsubscribe = Hub.listen("auth", ({ payload: { event, data }}) => {
switch (event) {
case "signIn":
setUser(data);
break;
case "signOut":
setUser(null);
break;
case "customOAuthState":
setCustomState(data);
}
});
getUser();
return unsubscribe;
}, []);
const getUser = async (): Promise => {
try {
const currentUser = await Auth.currentAuthenticatedUser();
setUser(currentUser);
} catch(error) {
console.error(error);
console.log("Not signed in");
}
};
return (
);
}
```
```javascript
import { useEffect, useState } from "react";
import { Text, View, Linking, Button } from "react-native";
import { Amplify, Auth, Hub } from "aws-amplify";
import awsconfig from "./aws-exports";
Amplify.configure(awsconfig);
export default function App() {
const [user, setUser] = useState(null);
const [customState, setCustomState] = useState(null);
useEffect(() => {
const unsubscribe = Hub.listen("auth", ({ payload: { event, data } }) => {
switch (event) {
case "signIn":
setUser(data);
break;
case "signOut":
setUser(null);
break;
case "customOAuthState":
setCustomState(data);
}
});
Auth.currentAuthenticatedUser()
.then(currentUser => setUser(currentUser))
.catch(() => console.log("Not signed in"));
return unsubscribe;
}, []);
return (
Auth.federatedSignIn({
provider: "LoginWithAmazon",
})
}
/>
Auth.federatedSignIn()} />
Auth.signOut()} />
{user && user.getUsername()}
);
}
```
### Deploying to Amplify Console
To deploy your app to Amplify Console with continuous deployment of the frontend and backend, please follow [these instructions](https://docs.aws.amazon.com/amplify/latest/userguide/environment-variables.html#creating-a-new-backend-environment-with-authentication-parameters).
### Redirect URLs
For *Sign in Redirect URI(s)* inputs, you can put one URI for local development and one for production. For example, in Expo: `exp://127.0.0.1:19000/--/` in dev and `myapp://` in production. The same is true for *Sign out redirect URI(s)*.
**Note:** if you have multiple redirect URI inputs, you'll need to handle both of them where you configure your Amplify project. For example:
```javascript
import awsConfig from "./aws-exports";
const isLocalhost = Boolean(__DEV__);
// Assuming you have two redirect URIs, and the first is for localhost and second is for production
const [
localRedirectSignIn,
productionRedirectSignIn,
] = awsConfig.oauth.redirectSignIn.split(",");
const [
localRedirectSignOut,
productionRedirectSignOut,
] = awsConfig.oauth.redirectSignOut.split(",");
const updatedAwsConfig = {
...awsConfig,
oauth: {
...awsConfig.oauth,
redirectSignIn: isLocalhost ? localRedirectSignIn : productionRedirectSignIn,
redirectSignOut: isLocalhost ? localRedirectSignOut : productionRedirectSignOut,
}
}
Amplify.configure(updatedAwsConfig);
```
For React Native applications, you need to define a custom URL scheme for your application before testing locally or publishing to the app store. This is different for Expo or vanilla React Native. For Expo, follow the steps in [Expo Linking Guide](https://docs.expo.io/guides/linking/). For vanilla React Native, follow the steps in [React Native Linking Guide](https://reactnative.dev/docs/linking). After completing those steps, assuming you are using `myapp` as the name of your URL Scheme (or whatever friendly name you have chosen), you will use these URLs as *Sign in Redirect URI(s)* and/or *Sign out redirect URI(s)* inputs. Your URIs could look like any of these:
- `myapp://`
- `exp://127.0.0.1:19000/--/` (Local development if your app is running [in the Expo client](https://docs.expo.io/versions/latest/workflow/linking/#linking-to-your-app)).
*React Native - iOS - Info.plist*
```xml
CFBundleURLTypesCFBundleURLSchemesmyapp
```
*React Native - Android - AndroidManifest.xml*
- Set the `launchMode` of MainActivity to `singleTask`
- Add new intent filter (below) with `scheme="myapp"`
```xml
```
### Full Samples
**Note for iOS Apps**
In order for Amplify to listen for data from Cognito when linking back to your app, you will need to setup the `Linking` module in `AppDelegate.m` (see [React Native docs](https://reactnative.dev/docs/linking#enabling-deep-links) for more information):
```objectivec
#import
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary *)options
{
return [RCTLinkingManager application:application openURL:url options:options];
}
```
**In-App Browser Setup (optional, but recommended)**
By default, Amplify will open the Cognito Hosted UI in Safari/Chrome, but you can override that behavior by providing a custom `urlOpener`. The sample below uses [react-native-inappbrowser-reborn](https://github.com/proyecto26/react-native-inappbrowser), but you can use any other in-app browser available.
**Sample**
```ts
import { useEffect, useState } from 'react';
import { Button, Linking, Text, View } from 'react-native';
import InAppBrowser from 'react-native-inappbrowser-reborn';
import { Amplify, Auth, Hub } from 'aws-amplify';
import { CognitoHostedUIIdentityProvider } from '@aws-amplify/auth';
import awsconfig from './aws-exports';
async function urlOpener(url: string, redirectUrl: string): Promise {
await InAppBrowser.isAvailable();
const authSessionResult = await InAppBrowser.openAuth(url, redirectUrl, {
showTitle: false,
enableUrlBarHiding: true,
enableDefaultShare: false,
ephemeralWebSession: false,
});
if (authSessionResult.type === 'success') {
Linking.openURL(authSessionResult.url);
}
}
Amplify.configure({
...awsconfig,
oauth: {
...awsconfig.oauth,
urlOpener,
},
});
function App() {
const [user, setUser] = useState(null);
useEffect(() => {
Hub.listen('auth', ({ payload: { event, data } }) => {
switch (event) {
case 'signIn':
case 'cognitoHostedUI':
getUser();
break;
case 'signOut':
setUser(null);
break;
case 'signIn_failure':
case 'cognitoHostedUI_failure':
console.log('Sign in failure', data);
break;
}
});
getUser()
}, []);
const getUser = async (): Promise => {
try {
const userData = await Auth.currentAuthenticatedUser();
setUser(userData)
} catch(error) {
console.error(error);
console.log("Not signed in");
}
};
return (
User: {user ? JSON.stringify(user.attributes) : 'None'}
{user ? (
Auth.signOut()} />
) : (
<>
{/* Go to the Cognito Hosted UI */}
Auth.federatedSignIn()} />
{/* Go directly to a configured identity provider */}
Auth.federatedSignIn({ provider: CognitoHostedUIIdentityProvider.Facebook })} />
Auth.federatedSignIn({ provider: CognitoHostedUIIdentityProvider.Google })} />
Auth.federatedSignIn({ provider: CognitoHostedUIIdentityProvider.Amazon })} />
>
)}
);
}
export default App;
```
```js
import { useEffect, useState } from 'react';
import { Button, Linking, Text, View } from 'react-native';
import InAppBrowser from 'react-native-inappbrowser-reborn';
import { Amplify, Auth, Hub } from 'aws-amplify';
import { CognitoHostedUIIdentityProvider } from '@aws-amplify/auth';
import awsconfig from './aws-exports';
async function urlOpener(url, redirectUrl) {
await InAppBrowser.isAvailable();
const { type, url: newUrl } = await InAppBrowser.openAuth(url, redirectUrl, {
showTitle: false,
enableUrlBarHiding: true,
enableDefaultShare: false,
ephemeralWebSession: false,
});
if (type === 'success') {
Linking.openURL(newUrl);
}
}
Amplify.configure({
...awsconfig,
oauth: {
...awsconfig.oauth,
urlOpener,
},
});
function App() {
const [user, setUser] = useState(null);
useEffect(() => {
Hub.listen('auth', ({ payload: { event, data } }) => {
switch (event) {
case 'signIn':
case 'cognitoHostedUI':
getUser().then(userData => setUser(userData));
break;
case 'signOut':
setUser(null);
break;
case 'signIn_failure':
case 'cognitoHostedUI_failure':
console.log('Sign in failure', data);
break;
}
});
getUser().then(userData => setUser(userData));
}, []);
function getUser() {
return Auth.currentAuthenticatedUser()
.then(userData => userData)
.catch(() => console.log('Not signed in'));
}
return (
User: {user ? JSON.stringify(user.attributes) : 'None'}
{user ? (
Auth.signOut()} />
) : (
<>
{/* Go to the Cognito Hosted UI */}
Auth.federatedSignIn()} />
{/* Go directly to a configured identity provider */}
Auth.federatedSignIn({ provider: CognitoHostedUIIdentityProvider.Facebook })} />
Auth.federatedSignIn({ provider: CognitoHostedUIIdentityProvider.Google })} />
Auth.federatedSignIn({ provider: CognitoHostedUIIdentityProvider.Amazon })} />
>
)}
);
}
export default App;
```
import all2 from "/src/fragments/lib/auth/js/react-native-withoauth.mdx";
**In-App Browser Setup (optional, but recommended)**
By default, Amplify will open the Cognito Hosted UI in Safari/Chrome, but you can override that behavior by providing a custom `urlOpener`. The sample below uses Expo's [WebBrowser.openAuthSessionAsync](https://docs.expo.io/versions/v37.0.0/sdk/webbrowser/).
**Sample**
```ts
import { useEffect, useState } from "react";
import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View, Linking, Button } from "react-native";
import * as WebBrowser from "expo-web-browser";
import { Amplify, Hub, Auth } from "aws-amplify";
import { CognitoHostedUIIdentityProvider } from "@aws-amplify/auth";
import awsconfig from "./src/aws-exports";
const isLocalHost = Boolean(__DEV__);
const [localRedirectSignIn, productionRedirectSignIn] =
awsconfig.oauth.redirectSignIn.split(",");
const [localRedirectSignOut, productionRedirectSignOut] =
awsconfig.oauth.redirectSignOut.split(",");
async function urlOpener(url: string, redirectUrl: string): Promise {
const authSessionResult = await WebBrowser.openAuthSessionAsync(
url,
redirectUrl
);
if (authSessionResult.type === "success" && Platform.OS === "ios") {
WebBrowser.dismissBrowser();
return Linking.openURL(authSessionResult.url);
}
}
const updatedConfig = {
...awsconfig,
oauth: {
...awsconfig.oauth,
redirectSignIn: isLocalHost
? localRedirectSignIn
: productionRedirectSignIn,
redirectSignOut: isLocalHost
? localRedirectSignOut
: productionRedirectSignOut,
urlOpener,
},
};
Amplify.configure(updatedConfig);
export default function App() {
const [user, setUser] = useState(null);
const [customState, setCustomState] = useState(null);
useEffect(() => {
const unsubscribe = Hub.listen("auth", ({ payload: { event, data }}) => {
console.log("event", event);
console.log("data", data);
switch (event) {
case "signIn":
setUser(data);
break;
case "signOut":
setUser(null);
break;
case "customOAuthState":
setCustomState(data);
break;
}
});
getUser();
return unsubscribe;
}, []);
const getUser = async (): Promise => {
try {
const currentUser = await Auth.currentAuthenticatedUser();
setUser(currentUser);
} catch(error) {
console.error(error);
console.log("Not signed in");
}
};
return (
Auth.federatedSignIn()} />
Auth.federatedSignIn({
provider: CognitoHostedUIIdentityProvider.Facebook,
})
}
/>
Auth.federatedSignIn({
provider: CognitoHostedUIIdentityProvider.Google,
})
}
/>
Auth.federatedSignIn({
provider: CognitoHostedUIIdentityProvider.Amazon,
})
}
/>
Auth.federatedSignIn({
provider: CognitoHostedUIIdentityProvider.Apple,
})
}
/>
Auth.signOut()} />
{user && user.getUsername()}
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
```
```js
import { useEffect, useState } from "react";
import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View, Linking, Button } from "react-native";
import * as WebBrowser from "expo-web-browser";
import { Amplify, Hub, Auth } from "aws-amplify";
import { CognitoHostedUIIdentityProvider } from "@aws-amplify/auth";
import awsconfig from "./src/aws-exports";
const isLocalHost = Boolean(__DEV__);
const [localRedirectSignIn, productionRedirectSignIn] =
awsconfig.oauth.redirectSignIn.split(",");
const [localRedirectSignOut, productionRedirectSignOut] =
awsconfig.oauth.redirectSignOut.split(",");
async function urlOpener(url, redirectUrl) {
const { type, url: newUrl } = await WebBrowser.openAuthSessionAsync(
url,
redirectUrl
);
if (type === "success" && Platform.OS === "ios") {
WebBrowser.dismissBrowser();
return Linking.openURL(newUrl);
}
}
const updatedConfig = {
...awsconfig,
oauth: {
...awsconfig.oauth,
redirectSignIn: isLocalHost
? localRedirectSignIn
: productionRedirectSignIn,
redirectSignOut: isLocalHost
? localRedirectSignOut
: productionRedirectSignOut,
urlOpener,
},
};
Amplify.configure(updatedConfig);
export default function App() {
const [user, setUser] = useState(null);
const [customState, setCustomState] = useState(null);
useEffect(() => {
const unsubscribe = Hub.listen("auth", ({ payload: { event, data } }) => {
console.log("event", event);
console.log("data", data);
switch (event) {
case "signIn":
setUser(data);
break;
case "signOut":
setUser(null);
break;
case "customOAuthState":
setCustomState(data);
break;
}
});
Auth.currentAuthenticatedUser()
.then((currentUser) => setUser(currentUser))
.catch(() => console.log("Not signed in"));
return unsubscribe;
}, []);
return (
Auth.federatedSignIn()} />
Auth.federatedSignIn({
provider: CognitoHostedUIIdentityProvider.Facebook,
})
}
/>
Auth.federatedSignIn({
provider: CognitoHostedUIIdentityProvider.Google,
})
}
/>
Auth.federatedSignIn({
provider: CognitoHostedUIIdentityProvider.Amazon,
})
}
/>
Auth.federatedSignIn({
provider: CognitoHostedUIIdentityProvider.Apple,
})
}
/>
Auth.signOut()} />
{user && user.getUsername()}
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
```
import all3 from "/src/fragments/lib/auth/js/react-native-withoauth.mdx";