PageSourceSearch

https://authress.io/knowledge-base/assets/js/e8e19c63.90293fb2.js

js authress.io collected 2026-09-24 18:32:01 UTC 16,295 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkAuthressKnowledgeBase=self.webpackChunkAuthressKnowledgeBase||[]).push([[7649],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var i=n(67294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?a(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):a(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,i,o=function(e,t){if(null==e)return{};var n,i,o={},a=Object.keys(e);for(i=0;i<a.length;i++)n=a[i],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i<a.length;i++)n=a[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=i.createContext({}),c=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},u=function(e){var t=c(e.components);return i.createElement(l.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},d=i.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=c(n),h=o,g=d["".concat(l,".").concat(h)]||d[h]||p[h]||a;return n?i.createElement(g,r(r({ref:t},u),{},{components:n})):i.createElement(g,r({ref:t},u))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,r=new Array(a);r[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s.mdxType="string"==typeof e?e:o,r[1]=s;for(var c=2;c<a;c++)r[c]=n[c];return i.createElement.apply(null,r)}return i.createElement.apply(null,n)}d.displayName="MDXCreateElement"},523:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>p,frontMatter:()=>a,metadata:()=>s,toc:()=>c});var i=n(87462),o=(n(67294),n(3905));const a={layout:"help",type:"article",title:"Custom Login Flow",description:"Setup a custom login flow passwordless login for your users",image:"../10-connecting-providers-idp/assets/oauth-logo.png",image_alt:"Integrating applications with a passwordless solution",category:"Technical help"},r=void 0,s={unversionedId:"authentication/custom-passwordless-login/index",id:"authentication/custom-passwordless-login/index",title:"Custom Login Flow",description:"Setup a custom login flow passwordless login for your users",source:"@site/docs/03-authentication/90-custom-passwordless-login/index.md",sourceDirName:"03-authentication/90-custom-passwordless-login",slug:"/authentication/custom-passwordless-login/",permalink:"/knowledge-base/docs/authentication/custom-passwordless-login/",draft:!1,editUrl:"https://gitlab.com/rhosys/authress-public-kb/knowledge-base/-/blob/main/docs/03-authentication/90-custom-passwordless-login/index.md",tags:[],version:"current",lastUpdatedAt:1772377859,formattedLastUpdatedAt:"Mar 1, 2026",frontMatter:{layout:"help",type:"article",title:"Custom Login Flow",description:"Setup a custom login flow passwordless login for your users",image:"../10-connecting-providers-idp/assets/oauth-logo.png",image_alt:"Integrating applications with a passwordless solution",category:"Technical help"},sidebar:"tutorialSidebar",previous:{title:"Tenants and organizations",permalink:"/knowledge-base/docs/authentication/tenants"},next:{title:"Linking user accounts",permalink:"/knowledge-base/docs/authentication/linked-user-accounts"}},l={},c=[{value:"Background: The Authress login flow",id:"background-the-authress-login-flow",level:2},{value:"Setup",id:"setup",level:2},{value:"1. Enable the Custom Passwordless Login Flow",id:"1-enable-the-custom-passwordless-login-flow",level:2},{value:"2. Update your application code",id:"2-update-your-application-code",level:2},{value:"3. Create your receiver",id:"3-create-your-receiver",level:2},{value:"3B. Using a code instead of the URL",id:"3b-using-a-code-instead-of-the-url",level:2},{value:"4. Authentication complete",id:"4-authentication-complete",level:2},{value:"Optional Automatic connection linking",id:"optional-automatic-connection-linking",level:2}],u={toc:c};
1function p(e){let{components:t,...a}=e;return(0,o.kt)("wrapper",(0,i.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"This guide details how to set up a passwordless flow. The same flow can be used to configure users to log in with an email address, a phone number, a one time use code, or any other custom flow you might have. You use Authress to generate a login url, then forward the user to that url via any mechanism that you might prefer. Authress supports this via an Authress Service Client has the permission to create tokens via a ",(0,o.kt)("a",{parentName:"p",href:"/knowledge-base/docs/authentication/connecting-providers-idp/oauth-setup-guide-part-3"},"custom connection configuration"),"."),(0,o.kt)("h2",{id:"background-the-authress-login-flow"},"Background: The Authress login flow"),(0,o.kt)("p",null,"The standard Authress login flow, starts in your web app. The user requests to login, which generates a login request using one of your configured ",(0,o.kt)("a",{parentName:"p",href:"https://authress.io/app/#/setup?focus=connections"},"Authress connections"),". The connectionId and applicationId are passed to the login SDK. This is a similar flow to what your application is already using to login with Authress, As a reminder these are the relevant SDK methods:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="(Application UI) Log a user into your application"',title:'"(Application',"UI)":!0,Log:!0,a:!0,user:!0,into:!0,your:!0,'application"':!0},"import { LoginClient } from '@authress/login';\nconst loginClient = new LoginClient({\n  // Both of these properties can be found and configured at:\n  // https://authress.io/app/#/manage?focus=applications\n  authressApiUrl: 'https://auth.yourdomain.com',\n  applicationId: 'YOUR_APPLICATION_ID'\n});\n\n// highlight-start\n// Instead of `authenticate()` we'll use `authenticateWithOneTimeCode()` instead:\nawait loginClient.authenticateWithOneTimeCode({ serviceClientId: 'SERVICE_CLIENT_ID' });\n// highlight-end\n")),(0,o.kt)("h2",{id:"setup"},"Setup"),(0,o.kt)("p",null,"The entire flow will look like this:"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Email passwordless setup",src:n(4551).Z,width:"1898",he
1ight:"1447"})),(0,o.kt)("h2",{id:"1-enable-the-custom-passwordless-login-flow"},"1. Enable the Custom Passwordless Login Flow"),(0,o.kt)("p",null,"The first step is to create a new service client. This client will be given the permissions to start and complete the flow. This prevents malicious users from abusing your passwordless flow to hijack user accounts."),(0,o.kt)("p",null,"Generate a new ",(0,o.kt)("a",{parentName:"p",href:"https://authress.io/app/#/setup?focus=clients"},"Authress Service Client"),". Enter a name for the client, and select the option to ",(0,o.kt)("inlineCode",{parentName:"p"},"Enable custom Authress user token generation"),". This allows this client to directly communicate with the Authress login API to request user identity tokens."),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Enable the legacy authorization service",src:n(17800).Z,width:"790",height:"565"})),(0,o.kt)("p",null,"Your Service Client represents your API that will send the passwordless one time code to the user's email or a code to their phone number. Enter the API's endpoint in the ",(0,o.kt)("inlineCode",{parentName:"p"},"Authorization Url")," property:"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Create a passwordless connection",src:n(33360).Z,width:"781",height:"372"})),(0,o.kt)("h2",{id:"2-update-your-application-code"},"2. Update your application code"),(0,o.kt)("p",null,"After the custom service client is created with the appropriate configuration, the next step is to update your application to enable the custom login flow. Instead of calling the ",(0,o.kt)("inlineCode",{parentName:"p"},"authenticate()")," method, instead call the ",(0,o.kt)("inlineCode",{parentName:"p"},"authenticateWithOneTimeCode()")," passing in the required properties:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="(Application UI) Authenticate using the Magic Link / One Time Code"',title:'"(Application',"UI)":!0,Authenticate:!0,using:!0,the:!0,Magic:!0,Link:!0,"/":!0,One:!0,Time:!0,'Code"':!0},"import { LoginClient } from '@authress/login';\nconst loginClient = new LoginClient({\n  // Both of these properties can be found and configured at:\n  // https://authress.io/app/#/manage?focus=applications\n  authressApiUrl: 'https://auth.yourdomain.com',\n  applicationId: 'YOUR_APPLICATION_ID'\n});\n\n// This will redirect the user to the specified connection login UI,\n// track their session with Authress, and then redirect back to your specified\nconst redirectUrl = window.location.href;\nconst result = await loginClient.authenticateWithOneTimeCode({ connectionId: 'SERVICE_CLIENT_ID', redirectUrl });\n\n// Next call your passwordless service client receiver with the necessary properties.\n// The name `generateUserLoginUrlAndSendEmail` is up to you, for this example we've used it for clarity.\nawait myApi.generateUserLoginUrlAndSendEmail({\n  emailAddress: '[email protected]',\n  authenticationRequestId: result.authenticationRequestId,\n  redirectUrl\n});\n")),(0,o.kt)("h2",{id:"3-create-your-receiver"},"3. Create your receiver"),(0,o.kt)("p",null,"At this point have the user's intent to login (the ",(0,o.kt)("inlineCode",{parentName:"p"},"authenticationRequestId"),") and the user's email are available. Now it is time to send the email and wait for the user to click the link."),(0,o.kt)("p",null,"Create your endpoint to generate the Authress one time code assertion, and send to the user:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Get User Login URL"',title:'"Get',User:!0,Login:!0,'URL"':!0},"import { ServiceClientTokenProvider } from '@authress/sdk';\n\n/**\n * authenticationRequestId {string} - This value is returned by the Authress Login SDK when calling the authenticateWithOneTimeCode\n * redirectUrl {string} - The redirectUrl is the same one passed to the Authress Login SDK. This must be the same value.\n */\nfunction generateUserLoginUrlAndSendEmail({ authenticationRequestId, redirectUrl, emailAddress }) {\n    const serviceClientId = 'SERVICE_CLIENT_ID';\n    const accessKey = 'SERVICE_CLIENT_ACCESS_KEY';\n\n    const tokenProvider = new ServiceClientTokenProvider(accessKey);\n    const authressLoginUrl = await tokenProvider.generateUserLoginUrl(redirectUrl, authenticationRequestId, serviceClientId, emailAddress.toLowerCase());\n    await sendEmailToUserEmail(emailAddress, authressLoginUrl);\n}\n")),(0,o.kt)("h2",{id:"3b-using-a-code-instead-of-the-url"},"3B. Using a code instead of the URL"),(0,o.kt)("p",null,"When using the email, Authress knows which user maps to that verified email address and can directly complete login using that URL."),(0,o.kt)("p",null,"If you want to send a code to an email, generate the code, and store a mapping in your database between the login URL and that code. Then display a screen to the user where they can enter the code. When the user receives your email with the code, they can enter it and receive back the login URL to complete login."),(0,o.kt)("p",null,"If you want to additionally use a phone number with a code, Authress doesn't know about phone numbers. The initial first step will be to save a mapping in your application for the user's phone number and map that to their email. When the user enters their phone number, send them SMS with the code, as before, complete the steps as above."),(0,o.kt)("h2",{id:"4-authentication-complete"},"4. Authentication complete"),(0,o.kt)("p",null,"When the user clicks on the link, they'll be logged into Authress, and be redirected back to the ",(0,o.kt)("inlineCode",{parentName:"p"},"redirectUrl")," you specified in the previous step."),(0,o.kt)("h2",{id:"optional-automatic-connection-linking"},"[Optional]"," Automatic connection linking"),(0,o.kt)("p",null,"When a user logs in Authress supports automatically linking the current login connection with other login connections if:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Both identity provider connections are set to enable ",(0,o.kt)("inlineCode",{parentName:"li"},"Automatic Linking")),(0,o.kt)("li",{parentName:"ol"},"Both generate user identities contain the ",(0,o.kt)("inlineCode",{parentName:"li"},"email_verified: true")," property.")),(0,o.kt)("p",null,"To enable ",(0,o.kt)("strong",{parentName:"p"},"Automatic Linking")," for both connections, go to Authress > ",(0,o.kt)("a",{parentName:"p",href:"https://authress.io/app/#/settings?focus=connections"},"Identity Connections")," > Select the connection > Advanced Tab > User Identity Linking. And then select: ",(0,o.kt)("strong",{parentName:"p"},"Automatically link identities whenever possible"),":"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Automatic User Identity Linking",src:n(57770).Z,width:"864",height:"277"})),(0,o.kt)("p",null,"Second, Authress will validate that the user identity that is returned from the provider has a trusted contact data. Not all providers return a contact email, and n
1ot all emails nor providers are trustworthy. If the provider is trusted via ",(0,o.kt)("strong",{parentName:"p"},"(1)")," above, and that the provider trusts the contact data from the user, usually the ",(0,o.kt)("strong",{parentName:"p"},"email")," address, then the user will automatically logged in with their already existing user identity."),(0,o.kt)("p",null,"As an example, if:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"A user logged in Google previously"),(0,o.kt)("li",{parentName:"ul"},"Google set the ",(0,o.kt)("inlineCode",{parentName:"li"},"email_verified")," property to ",(0,o.kt)("inlineCode",{parentName:"li"},"true")),(0,o.kt)("li",{parentName:"ul"},"The Authress preconfigured Google connection is set to enable ",(0,o.kt)("strong",{parentName:"li"},"Automatic Linking"))),(0,o.kt)("p",null,"And then the user logs into a second connection, such as your custom passwordless or another preconfigured connection AND:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"That connection has ",(0,o.kt)("strong",{parentName:"li"},"Automatic Linking")," enabled"),(0,o.kt)("li",{parentName:"ul"},"The user identity return from the provider includes the ",(0,o.kt)("inlineCode",{parentName:"li"},"email_verified")," property set to ",(0,o.kt)("inlineCode",{parentName:"li"},"true")," (This value is automatically set by the Authress SDKs.)")),(0,o.kt)("p",null,"Then the user will automatically be logged in with their previous user identity and the user ID assigned to the user will be the same."),(0,o.kt)("p",null,"If either connection is set to ",(0,o.kt)("strong",{parentName:"p"},"Explicit Linking")," or if either connection does not have the ",(0,o.kt)("inlineCode",{parentName:"p"},"email_verified")," attribute, then users can be linked using the ",(0,o.kt)("a",{parentName:"p",href:"/knowledge-base/docs/authentication/linked-user-accounts"},"Linking User Identity strategy guide"),"."))}p.isMDXComponent=!0},17800:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/create-service-client-bbbad05596d684b079cddde36392827e.png"},33360:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/legacy-connection-information-b22e26204e6b8ae6668b32fa45adfe3d.png"},4551:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/email-passwordless-flow-6e66b7d1f1ccf288aa447b70057f327a.png"},57770:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/automatic-user-identity-linking-7607ccfaeeacb6d7b7aad9afae0d271a.png"}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.