Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(expo/use-sso) Add redirectUrl parameter to startSSOFlow; remove expo partials #2005

Merged
merged 7 commits into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 0 additions & 78 deletions docs/_partials/expo/enterprise-sso-custom-flow.mdx

This file was deleted.

66 changes: 0 additions & 66 deletions docs/_partials/expo/oauth-custom-flow.mdx

This file was deleted.

82 changes: 81 additions & 1 deletion docs/custom-flows/enterprise-connections.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,86 @@ You must configure your application instance through the Clerk Dashboard for the
</Tab>

<Tab>
<Include src="_partials/expo/enterprise-sso-custom-flow" />
> [!IMPORTANT]
> Expo supports [SAML](/docs/authentication/enterprise-connections/overview#saml) Enterprise SSO, but does not support [OIDC](/docs/authentication/enterprise-connections/overview#oidc).

The following example **will both sign up _and_ sign in users**, eliminating the need for a separate sign-up page.

The following example:

1. Uses the [`useSSO()`](/docs/references/expo/use-sso) hook to access the `startSSOFlow()` method.
1. Calls the `startSSOFlow()` method with the `strategy` param set to `enterprise_sso` and the `identifier` param set to the user's email address that they provided. The optional `redirect_url` param is also set in order to redirect the user once they finish the authentication flow.
- If authentication is successful, the `setActive()` method is called to set the active session with the new `createdSessionId`.
- If authentication is not successful, you can handle the missing requirements, such as MFA, using the [`signIn`](/docs/references/javascript/sign-in/sign-in) or [`signUp`](/docs/references/javascript/sign-up/sign-up) object returned from `startSSOFlow()`, depending on if the user is signing in or signing up. These objects include properties, like `status`, that can be used to determine the next steps. See the respective linked references for more information.

```tsx {{ filename: 'app/(auth)/sign-in.tsx', collapsible: true }}
import React, { useEffect, useState } from 'react'
import * as WebBrowser from 'expo-web-browser'
import * as AuthSession from 'expo-auth-session'
import { useSSO } from '@clerk/clerk-expo'
import { View, Button, TextInput } 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 [email, setEmail] = useState('')

// Use the `useSSO()` hook to access the `startSSOFlow()` method
const { startSSOFlow } = useSSO()

const onPress = async () => {
try {
// Start the authentication process by calling `startSSOFlow()`
const { createdSessionId, setActive, signIn, signUp } = await startSSOFlow({
strategy: 'enterprise_sso',
identifier: email,
// Defaults to current path
redirectUrl: AuthSession.makeRedirectUri(),
})

// If sign in was successful, set the active session
if (createdSessionId) {
setActive!({ session: createdSessionId })
} else {
// If there is no `createdSessionId`,
// there are missing requirements, such as MFA
// Use the `signIn` or `signUp` returned from `startSSOFlow`
// to handle next steps
}
} 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>
<TextInput
value={email}
onChangeText={setEmail}
placeholder="Enter email"
placeholderTextColor="#666666"
/>
<Button title="Sign in with SAML" onPress={onPress} />
</View>
)
}
```
</Tab>
</Tabs>
70 changes: 69 additions & 1 deletion docs/custom-flows/oauth-connections.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,75 @@ You must configure your application instance through the Clerk Dashboard for the
</Tab>

<Tab>
<Include src="_partials/expo/oauth-custom-flow" />
The following example **will both sign up _and_ sign in users**, eliminating the need for a separate sign-up page.

The following example:

1. Uses the [`useSSO()`](/docs/references/expo/use-sso) hook to access the `startSSOFlow()` method.
1. Calls the `startSSOFlow()` method with the `strategy` param set to `oauth_google`, but you can use any of the [supported OAuth strategies](/docs/references/javascript/types/sso#oauth-strategy). The optional `redirect_url` param is also set in order to redirect the user once they finish the authentication flow.
- If authentication is successful, the `setActive()` method is called to set the active session with the new `createdSessionId`.
- If authentication is not successful, you can handle the missing requirements, such as MFA, using the [`signIn`](/docs/references/javascript/sign-in/sign-in) or [`signUp`](/docs/references/javascript/sign-up/sign-up) object returned from `startSSOFlow()`, depending on if the user is signing in or signing up. These objects include properties, like `status`, that can be used to determine the next steps. See the respective linked references for more information.

```tsx {{ filename: 'app/(auth)/sign-in.tsx', collapsible: true }}
import React, { useCallback, useEffect } from 'react'
import * as WebBrowser from 'expo-web-browser'
import * as AuthSession from 'expo-auth-session'
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()

// Use the `useSSO()` hook to access the `startSSOFlow()` method
const { startSSOFlow } = useSSO()

const onPress = useCallback(async () => {
try {
// Start the authentication process by calling `startSSOFlow()`
const { createdSessionId, setActive, signIn, signUp } = await startSSOFlow({
strategy: 'oauth_google',
// Defaults to current path
redirectUrl: AuthSession.makeRedirectUri(),
})

// If sign in was successful, set the active session
if (createdSessionId) {
setActive!({ session: createdSessionId })
} else {
// If there is no `createdSessionId`,
// there are missing requirements, such as MFA
// Use the `signIn` or `signUp` returned from `startSSOFlow`
// to handle next steps
}
} 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>
Expand Down
7 changes: 7 additions & 0 deletions docs/references/expo/use-sso.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ function startSSOFlow(startSSOFlowParams: StartSSOFlowParams): Promise<StartSSOF

---

- `redirectUrl?`
- `string`

The full URL or path to redirect to after the SSO flow is complete. If not specified, defaults to `sso-callback` path.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If not specified, defaults to sso-callback path.

But I don't see where the /sso-callback is used - users don't have to set anything up for this page, so if this /sso-callback path is actually hit behind the scenes, is this even worth mentioning?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If deep linking is working - in this case, for Android since iOS currently has a bug from our tests so far (expo/expo#34187)

And redirectUrl is not defined, then we'll navigate to sso-callback, and if they don't have this route configured on the app, it'll lead to a 404 - reason why I think it's worth mentioning the default

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused. The examples never set up a /sso-callback page. Whenever I tested, the flows just worked. There was never a 404.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On useOAuth, the default redirect URL used to be oauth-native-callback - however it's not mentioned in the previous guide:

https://github.com/clerk/javascript/blob/cab940862870e7961ba92e88ae3e6228b1893e97/packages/expo/src/hooks/useOAuth.ts#L59-L61

On useSSO, the default is now set to sso-callback

Whenever I tested, the flows just worked. There was never a 404.

I recognize this is confusing... and this is the behavior for iOS in development mode, as I mentioned it could be a bug with Expo (expo/expo#34187) in which we haven't tried to reproduce on production iOS builds

When using useSSO on Android, the deep link does happen correctly if you provide a valid URL. The behavior can be found in this PR description: clerk/javascript#5102 (comment)


---

- `unsafeMetadata?`
- [`SignUpUnsafeMetadata`](/docs/references/javascript/types/metadata#sign-up-unsafe-metadata)

Expand Down
Loading