Skip to content

Commit

Permalink
update oauth connections custom flow guide
Browse files Browse the repository at this point in the history
  • Loading branch information
alexisintech committed Jan 17, 2025
1 parent 2411868 commit 29c7a0b
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 149 deletions.
125 changes: 125 additions & 0 deletions docs/_partials/expo/sso-custom-flow.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<Tabs items={["With OAuth", "With SAML"]}>
<Tab>
The following example demonstrates how to create a custom SSO sign-in flow for [Google accounts](/docs/authentication/social-connections/google).

```tsx {{ filename: 'app/(auth)/sign-in.tsx', collapsible: true }}
import React, { useCallback, useEffect } from 'react'
import * as WebBrowser from 'expo-web-browser'
import * as Linking from 'expo-linking'
import { useSSO } from '@clerk/clerk-expo'
import { View, Button } from 'react-native'

export const useWarmUpBrowser = () => {
useEffect(() => {
// Preloads the browser for Android devices to reduce authentication load time
// See: https://docs.expo.dev/guides/authentication/#improving-user-experience
void WebBrowser.warmUpAsync()
return () => {
// Cleanup: closes browser when component unmounts
void WebBrowser.coolDownAsync()
}
}, [])
}

// Handle any pending authentication sessions
WebBrowser.maybeCompleteAuthSession()

export default function Page() {
useWarmUpBrowser()

const { startSSOFlow } = useSSO({ strategy: 'oauth_google' })

const onPress = useCallback(async () => {
try {
const { createdSessionId, setActive, signIn, signUp } = await startSSOFlow({
// URL to redirect to after successful authentication
// Must match the scheme defined in app.json
redirectUrl: Linking.createURL('/dashboard', { scheme: 'myapp' }),
})

// If sign in was successful, set the active session
if (createdSessionId) {
setActive!({ session: createdSessionId })
} else {
// Use `signIn` or `signUp` returned from `startSSOFlow`
// for next steps, such as MFA
}
} catch (err) {
// See https://clerk.com/docs/custom-flows/error-handling
// for more info on error handling
console.error(JSON.stringify(err, null, 2))
}
}, [])

return (
<View>
<Button title="Sign in with Google" onPress={onPress} />
</View>
)
}
```
</Tab>

<Tab>
The following example demonstrates how to create a custom SSO sign-in flow with [SAML](docs/authentication/enterprise-connections/overview#saml).

```tsx {{ filename: 'app/(auth)/sign-in.tsx', collapsible: true }}
import React, { useCallback, useEffect } from 'react'
import * as WebBrowser from 'expo-web-browser'
import * as Linking from 'expo-linking'
import { useSSO } from '@clerk/clerk-expo'
import { View, Button } from 'react-native'

export const useWarmUpBrowser = () => {
useEffect(() => {
// Preloads the browser for Android devices to reduce authentication load time
// See: https://docs.expo.dev/guides/authentication/#improving-user-experience
void WebBrowser.warmUpAsync()
return () => {
// Cleanup: closes browser when component unmounts
void WebBrowser.coolDownAsync()
}
}, [])
}

// Handle any pending authentication sessions
WebBrowser.maybeCompleteAuthSession()

export default function Page() {
useWarmUpBrowser()

const { startSSOFlow } = useSSO({ strategy: 'enterprise_sso', identifier: 'email' })

const onPress = useCallback(async () => {
try {
const { createdSessionId, setActive, signIn, signUp } = await startSSOFlow({
// URL to redirect to after successful authentication
// Must match the scheme defined in app.json
redirectUrl: Linking.createURL('/dashboard', { scheme: 'myapp' }),
// User identifier with a email domain that matches a enterprise connection
identifier: 'email',
})

// If sign in was successful, set the active session
if (createdSessionId) {
setActive!({ session: createdSessionId })
} else {
// Use `signIn` or `signUp` returned from `startSSOFlow`
// for next steps, such as MFA
}
} catch (err) {
// See https://clerk.com/docs/custom-flows/error-handling
// for more info on error handling
console.error(JSON.stringify(err, null, 2))
}
}, [])

return (
<View>
<Button title="Sign in with Google" onPress={onPress} />
</View>
)
}
```
</Tab>
</Tabs>
35 changes: 19 additions & 16 deletions docs/custom-flows/oauth-connections.mdx
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
---
title: Build a custom flow for authenticating with OAuth connections
description: Learn how to use the Clerk API to build a custom sign-up and sign-in flow that supports OAuth connections.
title: Build a custom flow for authenticating with SSO connections
description: Learn how to use the Clerk API to build a custom sign-up and sign-in flow that supports SSO connections.
---

<Include src="_partials/custom-flows-callout" />

## Before you start

You must configure your application instance through the Clerk Dashboard for the social connection(s) that you want to use, as described at [the top of the OAuth guide](/docs/authentication/social-connections/oauth#configuration).
You must configure your application instance through the Clerk Dashboard for the SSO connection that you want to use.

- For OAuth SSO, refer to [this guide](/docs/authentication/social-connections/oauth#enable-a-social-connection).
- For Enterprise SSO, refer to [this guide](/docs/authentication/enterprise-connections/overview).

## Create the sign-up and sign-in flow

When using OAuth, the sign-up and sign-in flows are equivalent.
When using SSO, the sign-up and sign-in flows are equivalent.

<Tabs items={["Next.js", "Expo", "iOS (beta)"]}>
<Tab>
A successful OAuth flow consists of the following steps:
A successful SSO flow consists of the following steps:

1. Start the OAuth flow by calling [`SignIn.authenticateWithRedirect(params)`](/docs/references/javascript/sign-in/authenticate-with#authenticate-with-redirect) or [`SignUp.authenticateWithRedirect(params)`](/docs/references/javascript/sign-up/authenticate-with#authenticate-with-redirect). Both of these methods require a `redirectUrl` param, which is the URL that the browser will be redirected to once the user authenticates with the OAuth provider.
1. Start the SSO flow by calling [`SignIn.authenticateWithRedirect(params)`](/docs/references/javascript/sign-in/authenticate-with#authenticate-with-redirect) or [`SignUp.authenticateWithRedirect(params)`](/docs/references/javascript/sign-up/authenticate-with#authenticate-with-redirect). Both of these methods require a `redirectUrl` param, which is the URL that the browser will be redirected to once the user authenticates with the OAuth provider.
1. Create a route at the URL that the `redirectUrl` param points to. The following example names this route `/sso-callback`. This route should call the [`Clerk.handleRedirectCallback()`](/docs/references/javascript/clerk/handle-navigation#handle-redirect-callback) method or simply render the prebuilt [`<AuthenticateWithRedirectCallback/>`](/docs/components/control/authenticate-with-callback) component.

The following example shows two files:

1. The sign-in page where the user can start the OAuth flow.
1. The SSO callback page where the OAuth flow is completed.
1. The sign-in page where the user can start the SSO flow.
1. The SSO callback page where the SSO flow is completed.

<CodeBlockTabs options={["Sign in page", "SSO callback page"]}>
```tsx {{ filename: 'app/sign-in/page.tsx' }}
Expand Down Expand Up @@ -90,7 +93,7 @@ When using OAuth, the sign-up and sign-in flows are equivalent.

### Build the flow

<Include src="_partials/expo/oauth-custom-flow" />
<Include src="_partials/expo/sso-custom-flow" />
</Tab>

<Tab>
Expand Down Expand Up @@ -159,9 +162,9 @@ When using OAuth, the sign-up and sign-in flows are equivalent.
</Tab>
</Tabs>

## OAuth account transfer flows
## SSO account transfer flows

It is common for users who are authenticating with OAuth to use a sign-in button when they mean to sign-up, and vice versa. For those cases, the `SignIn` and `SignUp` objects have a `transferable` status that indicates whether the user can be transferred to the other flow.
It is common for users who are authenticating with SSO to use a sign-in button when they mean to sign-up, and vice versa. For those cases, the `SignIn` and `SignUp` objects have a `transferable` status that indicates whether the user can be transferred to the other flow.

**If you would like to keep your sign-in and sign-up flows completely separate, then you can skip this section.**

Expand All @@ -176,7 +179,7 @@ The following example demonstrates how to handle these cases in your sign-in flo
import { OAuthStrategy } from '@clerk/types'
import { useSignIn, useSignUp } from '@clerk/nextjs'

export default function OauthSignIn() {
export default function SSOSignIn() {
const { signIn } = useSignIn()
const { signUp, setActive } = useSignUp()

Expand All @@ -194,7 +197,7 @@ The following example demonstrates how to handle these cases in your sign-in flo
if (!signIn || !signUp) return null

// If the user has an account in your application, but does not yet
// have an OAuth account connected to it, you can transfer the OAuth
// have an SSO account connected to it, you can transfer the SSO
// account to the existing user account.
const userExistsButNeedsToSignIn =
signUp.verifications.externalAccount.status === 'transferable' &&
Expand All @@ -210,9 +213,9 @@ The following example demonstrates how to handle these cases in your sign-in flo
}
}

// If the user has an OAuth account but does not yet
// If the user has an SSO account but does not yet
// have an account in your app, you can create an account
// for them using the OAuth information.
// for them using the SSO information.
const userNeedsToBeCreated = signIn.firstFactorVerification.status === 'transferable'

if (userNeedsToBeCreated) {
Expand All @@ -227,7 +230,7 @@ The following example demonstrates how to handle these cases in your sign-in flo
}
} else {
// If the user has an account in your application
// and has an OAuth account connected to it, you can sign them in.
// and has an SSO account connected to it, you can sign them in.
signInWith(strategy)
}
}
Expand Down
134 changes: 1 addition & 133 deletions docs/references/expo/use-sso.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -69,136 +69,4 @@ It accepts the following parameters (`StartSSOFlowParams`):
## How to use the `useSSO()` hook
<Tabs items={["With OAuth", "With SAML"]}>
<Tab>
The following example demonstrates how to create a custom SSO sign-in flow for [Google accounts](/docs/authentication/social-connections/google).
The `useSSO()` hook is used to create a new SSO flow with the `oauth_google` strategy. When the user presses the sign-in button, the `startSSOFlow()` method is called. If sign-in is successful, `createdSessionId` is used to set the active session. The `redirectUrl` parameter is used to specify the URL to redirect to after the SSO flow is complete.
If sign-in isn't successful, the `signIn` or `signUp` method returned from `startSSOFlow()` can be used to further authenticate the user.
```tsx {{ filename: 'app/(auth)/sign-in.tsx', collapsible: true }}
import React, { useCallback, useEffect } from 'react'
import * as WebBrowser from 'expo-web-browser'
import * as Linking from 'expo-linking'
import { useSSO } from '@clerk/clerk-expo'
import { View, Button } from 'react-native'

export const useWarmUpBrowser = () => {
useEffect(() => {
// Preloads the browser for Android devices to reduce authentication load time
// See: https://docs.expo.dev/guides/authentication/#improving-user-experience
void WebBrowser.warmUpAsync()
return () => {
// Cleanup: closes browser when component unmounts
void WebBrowser.coolDownAsync()
}
}, [])
}

// Handle any pending authentication sessions
WebBrowser.maybeCompleteAuthSession()

export default function Page() {
useWarmUpBrowser()

const { startSSOFlow } = useSSO({ strategy: 'oauth_google' })

const onPress = useCallback(async () => {
try {
const { createdSessionId, setActive } = await startSSOFlow({
// Specify redirect URL after successful authentication
// Must match the scheme defined in app.json
redirectUrl: Linking.createURL('/dashboard', { scheme: 'myapp' }),
})

if (createdSessionId) {
// If sign in was successful, set the active session
setActive!({ session: createdSessionId })
} else {
// Use signIn or signUp returned from startSSOFlow
// for next steps, such as MFA
}
} catch (err) {
// See https://clerk.com/docs/custom-flows/error-handling
// for more info on error handling
console.error(JSON.stringify(err, null, 2))
}
}, [])

return (
<View>
<Button title="Sign in with Google" onPress={onPress} />
</View>
)
}
```
</Tab>
<Tab>
The following example demonstrates how to create a custom SSO sign-in flow with [SAML](docs/authentication/enterprise-connections/overview#saml).
The `useSSO()` hook is used to create a new SSO flow with the `enterprise_sso` strategy and the [`identifier`](/docs/authentication/configuration/sign-up-sign-in-options#identifier) parameter set to the user's email address. When the user presses the sign-in button, the `startSSOFlow()` method is called. If sign-in is successful, `createdSessionId` is used to set the active session. The `redirectUrl` parameter is used to specify the URL to redirect to after the SSO flow is complete.
If sign-in isn't successful, the `signIn` or `signUp` method returned from `startSSOFlow()` can be used to further authenticate the user.
```tsx {{ filename: 'app/(auth)/sign-in.tsx', collapsible: true }}
import React, { useCallback, useEffect } from 'react'
import * as WebBrowser from 'expo-web-browser'
import * as Linking from 'expo-linking'
import { useSSO } from '@clerk/clerk-expo'
import { View, Button } from 'react-native'

export const useWarmUpBrowser = () => {
useEffect(() => {
// Preloads the browser for Android devices to reduce authentication load time
// See: https://docs.expo.dev/guides/authentication/#improving-user-experience
void WebBrowser.warmUpAsync()
return () => {
// Cleanup: closes browser when component unmounts
void WebBrowser.coolDownAsync()
}
}, [])
}

// Handle any pending authentication sessions
WebBrowser.maybeCompleteAuthSession()

export default function Page() {
useWarmUpBrowser()

const { startSSOFlow } = useSSO({ strategy: 'enterprise_sso', identifier: 'email' })

const onPress = useCallback(async () => {
try {
const { createdSessionId, setActive } = await startSSOFlow({
// Specify redirect URL after successful authentication
// Must match the scheme defined in app.json
redirectUrl: Linking.createURL('/dashboard', { scheme: 'myapp' }),
// User identifier with a email domain that matches a enterprise connection
identifier: 'email',
})

if (createdSessionId) {
// If sign in was successful, set the active session
setActive!({ session: createdSessionId })
} else {
// Use signIn or signUp returned from startOAuthFlow
// for next steps, such as MFA
}
} catch (err) {
// See https://clerk.com/docs/custom-flows/error-handling
// for more info on error handling
console.error(JSON.stringify(err, null, 2))
}
}, [])

return (
<View>
<Button title="Sign in with Google" onPress={onPress} />
</View>
)
}
```
</Tab>
</Tabs>
<Include src="_partials/expo/sso-custom-flow" />

0 comments on commit 29c7a0b

Please sign in to comment.