This guide walks through integrating email magic links using Stytch’s headless frontend SDKs. This approach gives you complete control over your UI while handling authentication logic on the frontend.Both and Organization-specific authentication flows are supported.
Discovery authentication
Organization-specific authentication
The Discovery flow is designed for situations where end users are signing up or logging in from a central landing page, and have not specified which they are trying to access.
In your application’s UI, introduce a way for end users to input their email and trigger a magicLinks.email.discovery.send() method call with the provided email.
Stytch will redirect the user to the Discovery RedirectURL you specified on the Redirect URLs page earlier. Exchange the token for a list of Discovered Organizations that the user can choose to log into.
export const DiscoveryAuthenticate = () => { const stytch = useStytchB2BClient(); useEffect(() => { const authenticate = async () => { const result = await stytch.authenticateByUrl(); if (result?.handled) { const { email_address, discovered_organizations } = result.data; // surface discovered organizations to user to select from console.log({ email_address, discovered_organizations }); } }; authenticate(); }, [stytch]); return <div>Loading</div>;};
An will be returned. The headless SDK will automatically set this in cookies and include it in follow-up calls.
3
Handle organization selection
When the end user selects an Organization to log into, call the exchange intermediate session method with the selected Organization ID.
You can optionally prompt the user for the name and slug of their new Organization. If not provided, Stytch will auto-generate them based on the end user’s email address.
If end users login via a page that indicates which Organization they’re trying to access (e.g., <org-slug>.your-app.com or your-app.com/team/<org-slug>), you can offer Organization-specific authentication.
Stytch will redirect the user to the Login or Signup RedirectURL that you specified in the magicLinks.email.loginOrSignup() call, or the relevant default in the Redirect URLs page of the Stytch Dashboard. The URL’s query parameters will contain stytch_token_type=multi_tenant_magic_links and an authentication token. Your application should extract the token from the URL and call the appropriate authentication method to finish the login process.
This guide walks through integrating magic links using Stytch’s backend SDKs. This approach handles all authentication logic on your backend, giving you complete control over the user experience.Both and Organization-specific authentication flows are supported.
Discovery authentication
Organization-specific authentication
The Discovery flow is designed for situations where end users are signing up or logging in from a central landing page, and have not specified which they are trying to access.
Stytch will make a callback to the discovery Redirect URL that you specified on the Redirect URLs page of the Stytch Dashboard. Since the same Redirect URL can be used for multiple authentication methods, the stytch_token_type in the callback parameters indicates which authentication flow the token belongs to. Your application should handle checking the stytch_token_type and calling the appropriate authentication method with the token.If your RedirectURL was http://localhost:3000/discovery you would add the following route to your application:
@app.route("/discovery", methods=["GET"])def discovery() -> str: token_type = request.args["stytch_token_type"] token = request.args["token"] if token_type != "discovery": # add handling for other discovery token types like discovery_oauth in the future return "Unsupported auth method", 400 resp = stytch_client.magic_links.discovery.authenticate( discovery_magic_links_token=token ) if resp.status_code != 200: return resp.error # store IST as cookie to include in org selection or creation request session['ist'] = resp.intermediate_session_token return resp.discovered_organizations
3
Handle organization selection
When the end user selects an Organization to log into, call the ExchangeIntermediateSession API with the selected organization_id and the intermediate_session_token returned from the discovery authenticate call.
@app.route("/login/<string:organization_id>", methods=["GET"])def login_to_org(organization_id): ist = session.get('ist') if not ist: return 500 resp = stytch_client.discovery.intermediate_sessions.exchange( intermediate_session_token=ist, organization_id=organization_id ) if resp.status_code != 200: return resp.error # Clear IST and set stytch session session.pop('ist', None) session['stytch_session'] = resp.session_token return resp.member
4
(Optional) Support organization creation
Allow users to create a new Organization instead of logging into an existing one.
You can optionally prompt the user for the name and slug of their new Organization. If not provided, Stytch will auto-generate them based on the end user’s email address.
@app.route("/create_org", methods=["GET"])def create_org() -> str: ist = session.get('ist') if not ist: return "No IST found", 400 resp = stytch_client.discovery.organizations.create( intermediate_session_token=ist ) if resp.status_code != 200: return resp.error # Clear IST and set stytch session session.pop('ist', None) session['stytch_session'] = resp.session_token return resp.member
If end users login via a page that indicates which Organization they’re trying to access (e.g., <org-slug>.your-app.com or your-app.com/team/<org-slug>), you can offer Organization-specific authentication.
After the user inputs their email on your Organization-specific login page, make a call to Stytch to initiate the magic link login flow with the provided email and the organization_id they are logging into.
Python
@app.route("/send_magic_link", methods=["POST"])def send_magic_link_login() -> str: email = request.form.get('email', None) organization_id = request.form.get('organization_id', None) if email is None or organization_id is None: return "Email and OrgID are required", 400 resp = stytch_client.magic_links.email.login_or_signup( email_address=email, organization_id=organization_id ) if resp.status_code != 200: return "Error sending EML", 500 return "Success"
2
Handle callback
Stytch will make a callback to the login or signup Redirect URL that you specified on the Redirect URLs page of the Stytch Dashboard, depending on if this is a returning user or a new user . Since the same Redirect URL can be used for multiple authentication methods, the stytch_token_type in the callback parameters indicates which authentication flow the token belongs to. Your application should handle checking the stytch_token_type and calling the appropriate authentication method with the token.If your RedirectURL was http://localhost:3000/authenticate you would add the following route to your application: