Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ To configure Native to Web SSO, you need to create and manage session_transfer_t

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">

Native to Web SSO supports the following SDKs: [Auth0 Android SDK](https://github.com/auth0/auth0.android/blob/main/EXAMPLES.md#native-to-web-sso-login-ea) and [Auth0 Swift SDK](https://github.com/auth0/Auth0.swift/blob/master/EXAMPLES.md#sso-credentials-ea).
Native to Web SSO supports the following SDKs: [Auth0 Android SDK](https://github.com/auth0/auth0.android/blob/main/EXAMPLES.md#native-to-web-sso-login-ea), [Auth0 Swift SDK](https://github.com/auth0/Auth0.swift/blob/master/EXAMPLES.md#sso-credentials-ea), and [Auth0 React Native SDK](https://github.com/auth0/react-native-auth0/blob/master/EXAMPLES.md#native-to-web-sso-early-access).

Native to Web SSO support is available in the following tools: [Auth0 Deploy CLI](/docs/deploy-monitor/deploy-cli-tool). [Auth0 Terraform Provider](/docs/deploy-monitor/auth0-terraform-provider) and [Auth0 CLI](https://auth0.github.io/auth0-cli/).

Expand Down Expand Up @@ -131,7 +131,7 @@ To facilitate this, your native application needs to exchange a refresh token fo

Use the [/token](https://auth0.com/docs/api/authentication/authorization-code-flow-with-pkce/get-token-pkce) endpoint with your native application to exchange the refresh token for a Session Transfer Token.

* Exchange a refresh token for a session transfer token using Swift or Android SDKs:
* Exchange a refresh token for a session transfer token using Swift, Android, or React Native SDKs:

<Tabs><Tab title="Swift SDK">

Expand All @@ -157,18 +157,53 @@ do {

</Tab><Tab title="Android SDK">

```swift lines
authentication
.ssoExchange("refresh_token")
.start(object : Callback<SSOCredentials, AuthenticationException> {
override fun onSuccess(result: SSOCredentials) {
// Use the sessionTransferToken token to authenticate the user in a web session in your app
```kotlin lines
secureCredentialsManager.getSsoCredentials(
mapOf(), // optional parameters
object : Callback<SSOCredentials, CredentialsManagerException> {
override fun onSuccess(result: SSOCredentials) {
// Use result.sessionTransferToken to authenticate
// the user in a web session in your app
}

override fun onFailure(error: CredentialsManagerException) {
// Handle error
}
}
)
```

</Tab><Tab title="React Native SDK">

```typescript lines
// Using Hooks
import { useAuth0 } from 'react-native-auth0';

override fun onFailure(exception: AuthenticationException) {
// Handle error
function MyComponent() {
const { getSSOCredentials } = useAuth0();

const openWebApp = async () => {
try {
const ssoCredentials = await getSSOCredentials();
// Use ssoCredentials.sessionTransferToken to authenticate
// the user in a web session in your app
console.log('Session Transfer Token:', ssoCredentials.sessionTransferToken);
} catch (error) {
console.error('Failed to get SSO credentials:', error);
}
})
};
}

// Using Auth0 class
import Auth0 from 'react-native-auth0';

const auth0 = new Auth0({
domain: '{yourDomain}',
clientId: '{yourClientId}',
});

const ssoCredentials = await auth0.credentialsManager.getSSOCredentials();
console.log('Session Transfer Token:', ssoCredentials.sessionTransferToken);
```

</Tab></Tabs>
Expand Down Expand Up @@ -470,28 +505,85 @@ Below are examples of web applications using Auth0 SDKs to redirect the `session
If your web application uses [Express.js](https://expressjs.com/) or the [Auth0 Express SDK](https://github.com/auth0/express-openid-connect), you can use the code below to add middleware support for `session_transfer_token`.

```javascript javascript lines
const config = {
const baseConfig = {
authRequired: false,
auth0Logout: true
};

// Default Middleware with no customizations
// app.use(auth(config));

// Extending the middleware to auto detect session_transfer_token
app.use((req, res, next) => {
const { session_transfer_token } = req.query;

// Create a new config for each request to avoid state leakage
const config = { ...baseConfig };

if (session_transfer_token) {
config.authorizationParams = {
session_transfer_token,
}
};
}

auth(config)(req, res, next);
});
```

##### Auth0 SPA SDK (@auth0/auth0-spa-js)

If your web application uses the [Auth0 SPA SDK](https://github.com/auth0/auth0-spa-js), you can pass the `session_transfer_token` to `loginWithRedirect()` via `authorizationParams`.

```typescript typescript lines
import { Auth0Client } from '@auth0/auth0-spa-js';

const auth0 = new Auth0Client({
domain: '{yourDomain}',
clientId: '{yourClientId}',
});

// Get session_transfer_token from URL query params (passed from native app)
const urlParams = new URLSearchParams(window.location.search);
const sessionTransferToken = urlParams.get('session_transfer_token');

// Use loginWithRedirect with the session_transfer_token
if (sessionTransferToken) {
await auth0.loginWithRedirect({
authorizationParams: {
session_transfer_token: sessionTransferToken,
redirect_uri: window.location.origin,
},
});
}
```

##### Auth0 React SDK (@auth0/auth0-react)

If your web application uses the [Auth0 React SDK](https://github.com/auth0/auth0-react), you can use `loginWithRedirect` from the `useAuth0` hook to pass the `session_transfer_token`.

```typescript typescript lines
import { useEffect } from 'react';
import { useAuth0 } from '@auth0/auth0-react';

function App() {
const { loginWithRedirect, isAuthenticated, isLoading } = useAuth0();

useEffect(() => {
if (isLoading || isAuthenticated) return;

const urlParams = new URLSearchParams(window.location.search);
const sessionTransferToken = urlParams.get('session_transfer_token');

if (sessionTransferToken) {
loginWithRedirect({
authorizationParams: {
session_transfer_token: sessionTransferToken,
},
});
}
}, [loginWithRedirect, isLoading, isAuthenticated]);

return <div>...</div>;
}
```

##### SAML and WS-Federation

If your web application uses <Tooltip tip="Security Assertion Markup Language (SAML): Standardized protocol allowing two parties to exchange authentication information without a password." cta="View Glossary" href="/docs/glossary?term=SAML">SAML</Tooltip> or <Tooltip tip="Security Assertion Markup Language (SAML): Standardized protocol allowing two parties to exchange authentication information without a password." cta="View Glossary" href="/docs/glossary?term=WS-Fed">WS-Fed</Tooltip> service provider and Auth0 as the <Tooltip tip="Web Service Federation (WS-Fed): Protocol for managing user identities across domains." cta="View Glossary" href="/docs/glossary?term=IdP">IdP</Tooltip>, you can send the `session_transfer_token` as an URL parameter to the Auth0 `/authorize` endpoint and the `redirect_uri` is the SAML or WS-Fed sign-in URL.
Expand Down Expand Up @@ -616,6 +708,41 @@ puts response.read_body
```
</AuthCodeGroup>

## Native to Web SSO with Organizations

Native to Web SSO supports [Organizations](/docs/manage-users/organizations). When a user authenticates with an organization in your native application, the session transfer token includes the organization context.

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">

When using Organizations with Native to Web SSO, the `organization` parameter in the web application's `/authorize` request must match the organization associated with the session transfer token. If there is a mismatch, authentication will fail and the user will be prompted to log in again.

</Callout>

To use Organizations with Native to Web SSO:

1. Authenticate the user in your native application with an organization:

```javascript javascript lines
// Native app login with organization
await authorize({
organization: 'org_abc123',
scope: 'openid profile email offline_access'
});
```

2. When redirecting to the web application, include the same organization in the `/authorize` request:

```bash bash lines
https://{yourDomain}/authorize?
client_id={yourWebClientId}&
redirect_uri={yourRedirectUri}&
response_type=code&
organization=org_abc123&
session_transfer_token=YOUR_SESSION_TRANSFER_TOKEN
```

If the organization in the `/authorize` request does not match the organization in the session transfer token, the session transfer token is rejected and the user is redirected to the login page to re-authenticate. A warning log is emitted in your tenant logs with the event description "Single Sign-On failed: Session Transfer Token organization mismatch detected."

## Session Transfer Token with Actions

Using `session_transfer_token` with [Actions](/docs/customize/actions) allows you to configure post-authentication risk detection and response capabilities to enhance user protection.
Expand All @@ -641,9 +768,63 @@ exports.onExecutePostLogin = async (event, api) => {
};
```

### Access Parent Refresh Token Metadata

Native to Web SSO allows you to access metadata from the parent refresh token that was used to initiate the SSO flow. This enables you to pass contextual information collected in the native application (such as device integrity, risk signals, or custom context) into the web session created from the `session_transfer_token`.

Auth0 exposes this information in Post Login Actions via the `event.session.session_transfer.parent_refresh_token.metadata` object. This enables secure, standardized propagation of metadata between platforms.

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">

**Example Use Case:** A mobile app collects risk data (device score, location, etc.) and stores it in the refresh token's metadata. When the native app initiates a Native to Web SSO flow, that metadata is automatically available in the corresponding web session via Actions.

</Callout>

The Action code below allows you to perform conditional access logic based on device trust metadata from the native application:

```javascript javascript lines
/**
* Handler that will be called during the execution of a PostLogin flow.
*
* @param {Event} event - Details about the user and the context in which they are logging in.
* @param {PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login.
*/
exports.onExecutePostLogin = async (event, api) => {
// Access metadata from the parent refresh token (native app)
const parentMetadata = event.session?.session_transfer?.parent_refresh_token?.metadata;

if (parentMetadata) {
const deviceTrustLevel = parentMetadata.device_trust;

if (deviceTrustLevel !== 'high') {
api.access.deny("Device trust level insufficient.");
}

// You can also add claims based on native app context
if (parentMetadata.subscription_tier) {
api.idToken.setCustomClaim('subscription_tier', parentMetadata.subscription_tier);
}
}
};
```

## Monitoring

You can monitor the Native to Web SSO activity by reviewing the Tenant [logs](/docs/deploy-monitor/logs).

### Token exchange logs

* `sertft` : Successful Refresh Token exchange. This log will correspond to a Native to Web SSO exchange when the `audience` field is `"audience":"urn:$auth0Domain:session_transfer"`
* `fertft`: Failed Refresh Token exchange. This log will correspond to a Native to Web SSO exchange when the `audience` field is `"audience": "urn:$auth0Domain:session_transfer"`

### Session transfer validation warning logs

Auth0 emits warning logs (`w`) when session transfer token validation fails during the `/authorize` request. These logs help you troubleshoot Native to Web SSO issues:

| Event Description | Cause |
|-------------------|-------|
| `Single Sign-On failed: Session Transfer Token not found or expired. This may indicate token reuse or expiration.` | The session transfer token was not found, has already been used, or has expired (tokens are single-use and expire after 1 minute). |
| `Single Sign-On failed: Session Transfer Token device binding validation failed due to IP/ASN mismatch.` | The IP address or ASN of the web request does not match the device binding configured for the session transfer token. |
| `Single Sign-On failed: Session Transfer Token organization mismatch detected.` | The `organization` parameter in the `/authorize` request does not match the organization in the session transfer token. |
| `Single Sign-On failed: Session Transfer Token user mismatch detected.` | A pre-existing Auth0 session belongs to a different user than the session transfer token. |
| `Single Sign-On failed: Parent refresh token not found. Session Transfer Token won't be used for session establishment.` | The parent refresh token used to create the session transfer token has been revoked or deleted. |
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ Edit the `MainActivity.kt` file to define the behavior of the `Subscribe to Memb

```kotlin lines
// Required imports
import com.auth0.android.authentication.storage.CredentialsManager
import com.auth0.android.authentication.storage.SecureCredentialsManager
import com.auth0.android.authentication.storage.SharedPreferencesStorage
import com.auth0.android.result.SSOCredentials
```
Expand Down Expand Up @@ -464,7 +464,8 @@ override fun onCreate(savedInstanceState: Bundle?) {
binding.buttonPatchMetadata.setOnClickListener { patchUserMetadata() }
binding.buttonSubscribe.setOnClickListener { launchSubscriptionFlow() }

credentialsManager = CredentialsManager(
secureCredentialsManager = SecureCredentialsManager(
this,
AuthenticationAPIClient(account),
SharedPreferencesStorage(this)
)
Expand All @@ -487,7 +488,7 @@ private fun loginWithBrowser() {
.withAudience("https://example.api.com")
.start(this, object : Callback<Credentials, AuthenticationException> {
override fun onSuccess(credentials: Credentials) {
credentialsManager.saveCredentials(credentials)
secureCredentialsManager.saveCredentials(credentials)
cachedCredentials = credentials
showSnackBar("Success: ${credentials.accessToken}")
updateUI()
Expand Down Expand Up @@ -518,42 +519,33 @@ To learn more, read [Set Up APIs](/docs/get-started/auth0-overview/set-up-apis).

```kotlin lines expandable
private fun launchSubscriptionFlow() {
credentialsManager.getCredentials(object : Callback<Credentials, CredentialsManagerException> {
override fun onSuccess(credentials: Credentials) {
val refreshToken = credentials.refreshToken ?: return

AuthenticationAPIClient(account)
.ssoExchange(refreshToken)
.start(object : Callback<SSOCredentials, AuthenticationException> {
override fun onSuccess(result: SSOCredentials) {
val sessionToken = result.sessionTransferToken

val cookieValue =
"auth0_session_transfer_token=$sessionToken; Path=/; Secure; HttpOnly; SameSite=None"
val cookieManager = android.webkit.CookieManager.getInstance()
cookieManager.setAcceptCookie(true)
cookieManager.setCookie("https://${getString(R.string.com_auth0_domain)}", cookieValue)

val webView = android.webkit.WebView(this@MainActivity)
webView.settings.javaScriptEnabled = true
webView.webViewClient = object : android.webkit.WebViewClient() {
override fun shouldOverrideUrlLoading(view: android.webkit.WebView?, url: String?) = false
}

webView.loadUrl("http://localhost:3000/join-membership")
setContentView(webView)
}
secureCredentialsManager.getSsoCredentials(
mapOf(), // optional parameters
object : Callback<SSOCredentials, CredentialsManagerException> {
override fun onSuccess(result: SSOCredentials) {
val sessionToken = result.sessionTransferToken

val cookieValue =
"auth0_session_transfer_token=$sessionToken; Path=/; Secure; HttpOnly; SameSite=None"
val cookieManager = android.webkit.CookieManager.getInstance()
cookieManager.setAcceptCookie(true)
cookieManager.setCookie("https://${getString(R.string.com_auth0_domain)}", cookieValue)

val webView = android.webkit.WebView(this@MainActivity)
webView.settings.javaScriptEnabled = true
webView.webViewClient = object : android.webkit.WebViewClient() {
override fun shouldOverrideUrlLoading(view: android.webkit.WebView?, url: String?) = false
}

override fun onFailure(error: AuthenticationException) {
showSnackBar("Failed to get session transfer token: ${error.getDescription()}")
}
})
}
webView.loadUrl("http://localhost:3000/join-membership")
setContentView(webView)
}

override fun onFailure(error: CredentialsManagerException) {
showSnackBar("Failed to load stored credentials: ${error.message}")
override fun onFailure(error: CredentialsManagerException) {
showSnackBar("Failed to get session transfer token: ${error.message}")
}
}
})
)
}
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ When a WebView or browser initiates a call to the `/authorize` endpoint, Auth0 d

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">

Native to Web SSSO does not change standard Auth0 [Single Sign-On](/docs/authenticate/single-sign-on) authentication.
Native to Web SSO does not change standard Auth0 [Single Sign-On](/docs/authenticate/single-sign-on) authentication.

</Callout>

Expand Down
Loading