Skip to content

Commit

Permalink
feat(clerk-expo): Introduce SAML support (#4880)
Browse files Browse the repository at this point in the history
Co-authored-by: Nicolas Lopes <[email protected]>
  • Loading branch information
LauraBeatris and NicolasLopes7 authored Jan 24, 2025
1 parent a26cf0f commit bd96d6c
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .changeset/selfish-worms-switch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@clerk/clerk-expo': minor
---

Introduce support for SSO with SAML

- Introduce `useSSO` hook to support a wider range of SSO flow types
- Deprecate `useOAuth` in favor of new `useSSO` hook
1 change: 1 addition & 0 deletions packages/expo/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ export {
useUser,
} from '@clerk/clerk-react';

export * from './useSSO';
export * from './useOAuth';
export * from './useAuth';
3 changes: 3 additions & 0 deletions packages/expo/src/hooks/useOAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export type StartOAuthFlowReturnType = {
authSessionResult?: WebBrowser.WebBrowserAuthSessionResult;
};

/**
* @deprecated Use `useSSO` instead
*/
export function useOAuth(useOAuthParams: UseOAuthFlowParams) {
const { strategy } = useOAuthParams || {};
if (!strategy) {
Expand Down
98 changes: 98 additions & 0 deletions packages/expo/src/hooks/useSSO.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { useSignIn, useSignUp } from '@clerk/clerk-react';
import type { EnterpriseSSOStrategy, OAuthStrategy, SetActive, SignInResource, SignUpResource } from '@clerk/types';
import * as AuthSession from 'expo-auth-session';
import * as WebBrowser from 'expo-web-browser';

import { errorThrower } from '../utils/errors';

export type StartSSOFlowParams = {
unsafeMetadata?: SignUpUnsafeMetadata;
} & (
| {
strategy: OAuthStrategy;
}
| {
strategy: EnterpriseSSOStrategy;
identifier: string;
}
);

export type StartSSOFlowReturnType = {
createdSessionId: string | null;
authSessionResult?: WebBrowser.WebBrowserAuthSessionResult;
setActive?: SetActive;
signIn?: SignInResource;
signUp?: SignUpResource;
};

export function useSSO() {
const { signIn, setActive, isLoaded: isSignInLoaded } = useSignIn();
const { signUp, isLoaded: isSignUpLoaded } = useSignUp();

async function startSSOFlow(startSSOFlowParams: StartSSOFlowParams): Promise<StartSSOFlowReturnType> {
if (!isSignInLoaded || !isSignUpLoaded) {
return {
createdSessionId: null,
signIn,
signUp,
setActive,
};
}

const { strategy, unsafeMetadata } = startSSOFlowParams ?? {};

/**
* Creates a redirect URL based on the application platform
* It must be whitelisted, either via Clerk Dashboard, or BAPI, in order
* to include the `rotating_token_nonce` on SSO callback
* @ref https://clerk.com/docs/reference/backend-api/tag/Redirect-URLs#operation/CreateRedirectURL
*/
const redirectUrl = AuthSession.makeRedirectUri({
path: 'sso-callback',
});

await signIn.create({
strategy,
redirectUrl,
...(startSSOFlowParams.strategy === 'enterprise_sso' ? { identifier: startSSOFlowParams.identifier } : {}),
});

const { externalVerificationRedirectURL } = signIn.firstFactorVerification;
if (!externalVerificationRedirectURL) {
return errorThrower.throw('Missing external verification redirect URL for SSO flow');
}

const authSessionResult = await WebBrowser.openAuthSessionAsync(externalVerificationRedirectURL.toString());
if (authSessionResult.type !== 'success' || !authSessionResult.url) {
return {
createdSessionId: null,
setActive,
signIn,
signUp,
};
}

const params = new URL(authSessionResult.url).searchParams;
const rotatingTokenNonce = params.get('rotating_token_nonce') ?? '';
await signIn.reload({ rotatingTokenNonce });

const userNeedsToBeCreated = signIn.firstFactorVerification.status === 'transferable';
if (userNeedsToBeCreated) {
await signUp.create({
transfer: true,
unsafeMetadata,
});
}

return {
createdSessionId: signUp.createdSessionId ?? signIn.createdSessionId,
setActive,
signIn,
signUp,
};
}

return {
startSSOFlow,
};
}

0 comments on commit bd96d6c

Please sign in to comment.