[{"data":1,"prerenderedAt":1140},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fidentity":180,"\u002Fdocs\u002Fidentity-surround":1135},[4,8,20,24,59,65,69,73,77,100,104,108,112,116,120,124,128,160,164,168,172,176],{"title":5,"path":6,"stem":7},"","\u002Fdocs","1.docs\u002Findex",{"title":9,"path":10,"stem":11,"children":12,"icon":19},"Getting Started","\u002Fdocs\u002Fgetting-started","1.docs\u002F01.getting-started\u002F1.index",[13,15],{"title":14,"path":10,"stem":11},"Bosca",{"title":16,"path":17,"stem":18},"Quickstart","\u002Fdocs\u002Fgetting-started\u002Fquickstart","1.docs\u002F01.getting-started\u002F2.quickstart",false,{"title":21,"path":22,"stem":23},"Kit","\u002Fdocs\u002Fkit","1.docs\u002F01.kit",{"title":25,"path":26,"stem":27,"children":28},"Content","\u002Fdocs\u002Fcontent","1.docs\u002F02.content\u002F1.index",[29,31,53],{"title":30,"path":26,"stem":27},"Content Strategy",{"title":32,"path":33,"stem":34,"children":35},"Metadata","\u002Fdocs\u002Fcontent\u002Fmetadata","1.docs\u002F02.content\u002F1.metadata\u002F1.index",[36,37,41,45,49],{"title":32,"path":33,"stem":34},{"title":38,"path":39,"stem":40},"Supplementary","\u002Fdocs\u002Fcontent\u002Fmetadata\u002Fsupplementary","1.docs\u002F02.content\u002F1.metadata\u002F2.supplementary",{"title":42,"path":43,"stem":44},"Documents","\u002Fdocs\u002Fcontent\u002Fmetadata\u002Fdocuments","1.docs\u002F02.content\u002F1.metadata\u002F3.documents",{"title":46,"path":47,"stem":48},"Guides","\u002Fdocs\u002Fcontent\u002Fmetadata\u002Fguides","1.docs\u002F02.content\u002F1.metadata\u002F4.guides",{"title":50,"path":51,"stem":52},"Bible","\u002Fdocs\u002Fcontent\u002Fmetadata\u002Fbible","1.docs\u002F02.content\u002F1.metadata\u002F5.bible",{"title":54,"path":55,"stem":56,"children":57},"Collections","\u002Fdocs\u002Fcontent\u002Fcollections","1.docs\u002F02.content\u002F2.collections\u002F1.index",[58],{"title":54,"path":55,"stem":56},{"title":60,"path":61,"stem":62,"children":63},"Workflows","\u002Fdocs\u002Fworkflows","1.docs\u002F03.workflows\u002F1.index",[64],{"title":60,"path":61,"stem":62},{"title":66,"path":67,"stem":68},"Search","\u002Fdocs\u002Fsearch","1.docs\u002F04.search",{"title":70,"path":71,"stem":72},"Profiles","\u002Fdocs\u002Fprofiles","1.docs\u002F05.profiles",{"title":74,"path":75,"stem":76},"Organizations","\u002Fdocs\u002Forganizations","1.docs\u002F06.organizations",{"title":78,"path":79,"stem":80,"children":81,"icon":99},"Engineering","\u002Fdocs\u002Fengineering","1.docs\u002F07.engineering\u002F1.index",[82,83,87,91,95],{"title":78,"path":79,"stem":80},{"title":84,"path":85,"stem":86},"Infrastructure","\u002Fdocs\u002Fengineering\u002Finfrastructure","1.docs\u002F07.engineering\u002F2.infrastructure",{"title":88,"path":89,"stem":90},"Backend Services","\u002Fdocs\u002Fengineering\u002Fservices","1.docs\u002F07.engineering\u002F3.services",{"title":92,"path":93,"stem":94},"Deployment","\u002Fdocs\u002Fengineering\u002Fdeployment","1.docs\u002F07.engineering\u002F4.deployment",{"title":96,"path":97,"stem":98},"Framework Modules","\u002Fdocs\u002Fengineering\u002Fframework","1.docs\u002F07.engineering\u002F5.framework","i-heroicons-wrench-screwdriver",{"title":101,"path":102,"stem":103},"Identity Management","\u002Fdocs\u002Fidentity","1.docs\u002F07.identity",{"title":105,"path":106,"stem":107},"Localization","\u002Fdocs\u002Flocalization","1.docs\u002F08.localization",{"title":109,"path":110,"stem":111},"Analytics","\u002Fdocs\u002Fanalytics","1.docs\u002F09.analytics",{"title":113,"path":114,"stem":115},"AI & Agents","\u002Fdocs\u002Fai","1.docs\u002F10.ai",{"title":117,"path":118,"stem":119},"Messaging & Email","\u002Fdocs\u002Fmessages","1.docs\u002F11.messages",{"title":121,"path":122,"stem":123},"Scheduler","\u002Fdocs\u002Fscheduler","1.docs\u002F12.scheduler",{"title":125,"path":126,"stem":127},"Backup & Restore","\u002Fdocs\u002Fbackup","1.docs\u002F13.backup",{"title":129,"path":130,"stem":131,"children":132},"Architecture","\u002Fdocs\u002Farchitecture","1.docs\u002F14.architecture\u002F1.index",[133,134,137,141,145,149,153,157],{"title":129,"path":130,"stem":131},{"title":92,"path":135,"stem":136},"\u002Fdocs\u002Farchitecture\u002Fdeployment","1.docs\u002F14.architecture\u002F2.deployment",{"title":138,"path":139,"stem":140},"Security","\u002Fdocs\u002Farchitecture\u002Fsecurity","1.docs\u002F14.architecture\u002F3.security",{"title":142,"path":143,"stem":144},"Telemetry","\u002Fdocs\u002Farchitecture\u002Ftelemetry","1.docs\u002F14.architecture\u002F4.telemetry",{"title":146,"path":147,"stem":148},"Administration","\u002Fdocs\u002Farchitecture\u002Fadministration","1.docs\u002F14.architecture\u002F5.administration",{"title":150,"path":151,"stem":152},"GraphQL Schema","\u002Fdocs\u002Farchitecture\u002Fgraphql","1.docs\u002F14.architecture\u002F6.graphql",{"title":154,"path":155,"stem":156},"Storage","\u002Fdocs\u002Farchitecture\u002Fstorage","1.docs\u002F14.architecture\u002F7.storage",{"title":105,"path":158,"stem":159},"\u002Fdocs\u002Farchitecture\u002Flocalization","1.docs\u002F14.architecture\u002F8.localization",{"title":161,"path":162,"stem":163},"Scripting","\u002Fdocs\u002Fscripting","1.docs\u002F15.scripting",{"title":165,"path":166,"stem":167},"Configuration","\u002Fdocs\u002Fconfiguration","1.docs\u002F16.configuration",{"title":169,"path":170,"stem":171},"Forms","\u002Fdocs\u002Fforms","1.docs\u002F17.forms",{"title":173,"path":174,"stem":175},"Segmentation & Campaigns","\u002Fdocs\u002Fsegmentation","1.docs\u002F18.segmentation",{"title":177,"path":178,"stem":179},"Devices & Push","\u002Fdocs\u002Fdevices","1.docs\u002F19.devices",{"id":181,"title":101,"body":182,"description":1129,"extension":1130,"meta":1131,"navigation":1132,"path":102,"seo":1133,"stem":103,"__hash__":1134},"docs\u002F1.docs\u002F07.identity.md",{"type":183,"value":184,"toc":1108},"minimark",[185,200,205,210,218,221,252,256,259,279,282,286,300,303,317,321,324,328,331,408,412,419,455,458,494,497,515,526,530,537,579,582,586,589,612,615,629,633,637,640,742,748,756,760,766,800,803,837,841,847,929,933,936,983,986,997,1001,1034,1038,1041,1064,1067,1104],[186,187,188,189,192,193,195,196,199],"p",{},"Bosca provides a complete identity management system covering user registration, authentication, credential management, and session handling. It is built on top of the ",[190,191,138],"a",{"href":139}," layer and integrates with ",[190,194,70],{"href":71}," and ",[190,197,198],{"href":118},"Messaging"," for a seamless user experience.",[201,202,204],"h2",{"id":203},"core-concepts","Core Concepts",[206,207,209],"h3",{"id":208},"principals","Principals",[186,211,212,213,217],{},"A ",[214,215,216],"strong",{},"Principal"," is a user identity in Bosca. Every principal has a unique ID, a verification status, and an optional link to a primary profile.",[186,219,220],{},"Key attributes:",[222,223,224,231,237,246],"ul",{},[225,226,227,230],"li",{},[214,228,229],{},"verified"," — whether the principal's email has been confirmed",[225,232,233,236],{},[214,234,235],{},"anonymous"," — whether the principal is an unauthenticated guest",[225,238,239,242,243],{},[214,240,241],{},"primaryProfileId"," — links the principal to their default ",[190,244,245],{"href":71},"Profile",[225,247,248,251],{},[214,249,250],{},"attributes"," — optional JSON metadata attached to the identity",[206,253,255],{"id":254},"credentials","Credentials",[186,257,258],{},"Each principal authenticates using one or more credentials. Bosca supports three credential types:",[222,260,261,267,273],{},[225,262,263,266],{},[214,264,265],{},"PASSWORD"," — passwords hashed with Argon2id (the modern default)",[225,268,269,272],{},[214,270,271],{},"PASSWORD_SCRYPT"," — passwords hashed with scrypt (for migrated accounts)",[225,274,275,278],{},[214,276,277],{},"OAUTH2"," — third-party provider tokens (Google, Facebook, Apple, or any OpenID Connect provider)",[186,280,281],{},"A single principal can have multiple credentials—for example, a password and a linked Google account.",[206,283,285],{"id":284},"groups-permissions","Groups & Permissions",[186,287,288,289,292,293,296,297,299],{},"Principals are assigned to ",[214,290,291],{},"Groups",", and groups receive ",[214,294,295],{},"Permissions"," on specific entities. See ",[190,298,138],{"href":139}," for full details on the permission model.",[186,301,302],{},"Groups have two types:",[222,304,305,311],{},[225,306,307,310],{},[214,308,309],{},"PRINCIPAL"," — created and managed by users or organizations",[225,312,313,316],{},[214,314,315],{},"SYSTEM"," — managed internally by Bosca (e.g., Administrators)",[201,318,320],{"id":319},"authentication-methods","Authentication Methods",[186,322,323],{},"Bosca supports several ways to authenticate:",[206,325,327],{"id":326},"password-login","Password Login",[186,329,330],{},"Users sign up with an identifier (typically an email) and a password. Passwords are hashed with Argon2id using BouncyCastle and are never stored in plain text.",[332,333,337],"pre",{"className":334,"code":335,"language":336,"meta":5,"style":5},"language-graphql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","mutation {\n  security {\n    login {\n      password(identifier: \"user@example.com\", password: \"secret\") {\n        token { token expiresAt }\n        principal { id verified }\n        refreshToken\n      }\n    }\n  }\n}\n","graphql",[338,339,340,348,354,360,366,372,378,384,390,396,402],"code",{"__ignoreMap":5},[341,342,345],"span",{"class":343,"line":344},"line",1,[341,346,347],{},"mutation {\n",[341,349,351],{"class":343,"line":350},2,[341,352,353],{},"  security {\n",[341,355,357],{"class":343,"line":356},3,[341,358,359],{},"    login {\n",[341,361,363],{"class":343,"line":362},4,[341,364,365],{},"      password(identifier: \"user@example.com\", password: \"secret\") {\n",[341,367,369],{"class":343,"line":368},5,[341,370,371],{},"        token { token expiresAt }\n",[341,373,375],{"class":343,"line":374},6,[341,376,377],{},"        principal { id verified }\n",[341,379,381],{"class":343,"line":380},7,[341,382,383],{},"        refreshToken\n",[341,385,387],{"class":343,"line":386},8,[341,388,389],{},"      }\n",[341,391,393],{"class":343,"line":392},9,[341,394,395],{},"    }\n",[341,397,399],{"class":343,"line":398},10,[341,400,401],{},"  }\n",[341,403,405],{"class":343,"line":404},11,[341,406,407],{},"}\n",[206,409,411],{"id":410},"oauth2-openid-connect","OAuth2 \u002F OpenID Connect",[186,413,414,415,418],{},"Bosca has built-in support for third-party authentication via OAuth2. Providers are configured in ",[338,416,417],{},"application.yaml"," and each provider specifies:",[222,420,421,429,437,443,449],{},[225,422,423,195,426],{},[338,424,425],{},"clientId",[338,427,428],{},"clientSecret",[225,430,431,195,434],{},[338,432,433],{},"authorizeUrl",[338,435,436],{},"accessTokenUrl",[225,438,439,442],{},[338,440,441],{},"userInfoUrl"," for fetching the user's profile",[225,444,445,448],{},[338,446,447],{},"scopes"," for the requested permissions",[225,450,451,454],{},[338,452,453],{},"callback"," URLs for redirect handling",[186,456,457],{},"Built-in provider adapters include:",[222,459,460,484],{},[225,461,462,465,466,469,470,473,474,473,477,473,480,483],{},[214,463,464],{},"Google \u002F Generic OIDC"," — uses the standard ",[338,467,468],{},"DefaultOauth2User"," model (parses ",[338,471,472],{},"given_name",", ",[338,475,476],{},"family_name",[338,478,479],{},"picture",[338,481,482],{},"email",")",[225,485,486,489,490,493],{},[214,487,488],{},"Facebook"," — uses a dedicated ",[338,491,492],{},"FacebookUser"," adapter that extracts the profile picture from Facebook's nested picture object",[186,495,496],{},"During OAuth2 login, Bosca:",[498,499,500,503,506,509,512],"ol",{},[225,501,502],{},"Redirects the user to the provider's authorize URL with a state token (cached for verification)",[225,504,505],{},"Receives the callback with an authorization code",[225,507,508],{},"Exchanges the code for an access token",[225,510,511],{},"Fetches user info from the provider",[225,513,514],{},"Creates or links the principal and issues a JWT session",[186,516,517,518,521,522,525],{},"OAuth2 flows also support ",[214,519,520],{},"signup tokens",", allowing users who authenticate via a provider to simultaneously join an ",[190,523,524],{"href":75},"Organization",".",[206,527,529],{"id":528},"refresh-tokens","Refresh Tokens",[186,531,532,533,536],{},"Login responses can include a ",[338,534,535],{},"refreshToken"," for long-lived sessions. Use it to obtain a new JWT without re-entering credentials:",[332,538,540],{"className":334,"code":539,"language":336,"meta":5,"style":5},"mutation {\n  security {\n    login {\n      refreshToken(refreshToken: \"...\") {\n        token { token expiresAt }\n      }\n    }\n  }\n}\n",[338,541,542,546,550,554,559,563,567,571,575],{"__ignoreMap":5},[341,543,544],{"class":343,"line":344},[341,545,347],{},[341,547,548],{"class":343,"line":350},[341,549,353],{},[341,551,552],{"class":343,"line":356},[341,553,359],{},[341,555,556],{"class":343,"line":362},[341,557,558],{},"      refreshToken(refreshToken: \"...\") {\n",[341,560,561],{"class":343,"line":368},[341,562,371],{},[341,564,565],{"class":343,"line":374},[341,566,389],{},[341,568,569],{"class":343,"line":380},[341,570,395],{},[341,572,573],{"class":343,"line":386},[341,574,401],{},[341,576,577],{"class":343,"line":392},[341,578,407],{},[186,580,581],{},"Expired refresh tokens are automatically cleaned up by the system.",[206,583,585],{"id":584},"jwt-tokens","JWT Tokens",[186,587,588],{},"All authenticated sessions use JWT tokens signed with HMAC-SHA256. Token configuration includes:",[222,590,591,600,606],{},[225,592,593,195,596,599],{},[214,594,595],{},"issuer",[214,597,598],{},"audience"," — validated on every request",[225,601,602,605],{},[214,603,604],{},"realm"," — the authentication realm",[225,607,608,611],{},[214,609,610],{},"expirationTimeInSeconds"," — configurable token lifetime (default: 3600s)",[186,613,614],{},"Bosca accepts tokens via:",[222,616,617,623,626],{},[225,618,619,622],{},[338,620,621],{},"Authorization: Bearer \u003Ctoken>"," header",[225,624,625],{},"Basic Auth (identifier and password)",[225,627,628],{},"Cookie-based sessions (for browser flows)",[201,630,632],{"id":631},"signup-verification","Signup & Verification",[206,634,636],{"id":635},"password-signup","Password Signup",[186,638,639],{},"New users register with an identifier, password, and profile information:",[332,641,643],{"className":334,"code":642,"language":336,"meta":5,"style":5},"mutation {\n  security {\n    signup {\n      password(\n        identifier: \"user@example.com\"\n        password: \"secret\"\n        profile: { \n          name: \"Jane Doe\" \n          attributes: [] \n          visibility: PUBLIC \n        }\n        tokens: [{ type: ORGANIZATION, token: \"invite-token\" }]\n      ) {\n        id\n        verified\n      }\n    }\n  }\n}\n",[338,644,645,649,653,658,663,668,673,678,683,688,693,698,704,710,716,722,727,732,737],{"__ignoreMap":5},[341,646,647],{"class":343,"line":344},[341,648,347],{},[341,650,651],{"class":343,"line":350},[341,652,353],{},[341,654,655],{"class":343,"line":356},[341,656,657],{},"    signup {\n",[341,659,660],{"class":343,"line":362},[341,661,662],{},"      password(\n",[341,664,665],{"class":343,"line":368},[341,666,667],{},"        identifier: \"user@example.com\"\n",[341,669,670],{"class":343,"line":374},[341,671,672],{},"        password: \"secret\"\n",[341,674,675],{"class":343,"line":380},[341,676,677],{},"        profile: { \n",[341,679,680],{"class":343,"line":386},[341,681,682],{},"          name: \"Jane Doe\" \n",[341,684,685],{"class":343,"line":392},[341,686,687],{},"          attributes: [] \n",[341,689,690],{"class":343,"line":398},[341,691,692],{},"          visibility: PUBLIC \n",[341,694,695],{"class":343,"line":404},[341,696,697],{},"        }\n",[341,699,701],{"class":343,"line":700},12,[341,702,703],{},"        tokens: [{ type: ORGANIZATION, token: \"invite-token\" }]\n",[341,705,707],{"class":343,"line":706},13,[341,708,709],{},"      ) {\n",[341,711,713],{"class":343,"line":712},14,[341,714,715],{},"        id\n",[341,717,719],{"class":343,"line":718},15,[341,720,721],{},"        verified\n",[341,723,725],{"class":343,"line":724},16,[341,726,389],{},[341,728,730],{"class":343,"line":729},17,[341,731,395],{},[341,733,735],{"class":343,"line":734},18,[341,736,401],{},[341,738,740],{"class":343,"line":739},19,[341,741,407],{},[186,743,744,745,747],{},"Signup tokens allow new users to automatically join an ",[190,746,524],{"href":75}," during registration. The supported token type is:",[222,749,750],{},[225,751,752,755],{},[214,753,754],{},"ORGANIZATION"," — joins the user to an organization",[206,757,759],{"id":758},"email-verification","Email Verification",[186,761,762,763,765],{},"After signup, Bosca sends a verification email through the ",[190,764,198],{"href":118}," system. The email contains a unique verification token that confirms ownership of the email address.",[332,767,769],{"className":334,"code":768,"language":336,"meta":5,"style":5},"mutation {\n  security {\n    signup {\n      passwordVerify(verificationToken: \"...\") \n    }\n  }\n}\n",[338,770,771,775,779,783,788,792,796],{"__ignoreMap":5},[341,772,773],{"class":343,"line":344},[341,774,347],{},[341,776,777],{"class":343,"line":350},[341,778,353],{},[341,780,781],{"class":343,"line":356},[341,782,657],{},[341,784,785],{"class":343,"line":362},[341,786,787],{},"      passwordVerify(verificationToken: \"...\") \n",[341,789,790],{"class":343,"line":368},[341,791,395],{},[341,793,794],{"class":343,"line":374},[341,795,401],{},[341,797,798],{"class":343,"line":380},[341,799,407],{},[186,801,802],{},"If the original email is missed, users can request it again:",[332,804,806],{"className":334,"code":805,"language":336,"meta":5,"style":5},"mutation {\n  security {\n    signup {\n      resendPasswordVerification(identifier: \"user@example.com\")\n    }\n  }\n}\n",[338,807,808,812,816,820,825,829,833],{"__ignoreMap":5},[341,809,810],{"class":343,"line":344},[341,811,347],{},[341,813,814],{"class":343,"line":350},[341,815,353],{},[341,817,818],{"class":343,"line":356},[341,819,657],{},[341,821,822],{"class":343,"line":362},[341,823,824],{},"      resendPasswordVerification(identifier: \"user@example.com\")\n",[341,826,827],{"class":343,"line":368},[341,828,395],{},[341,830,831],{"class":343,"line":374},[341,832,401],{},[341,834,835],{"class":343,"line":380},[341,836,407],{},[201,838,840],{"id":839},"password-recovery","Password Recovery",[186,842,843,844,846],{},"Bosca includes a complete forgot-password flow that integrates with ",[190,845,198],{"href":118},":",[498,848,849,889],{},[225,850,851,854,855],{},[214,852,853],{},"Request reset"," — triggers an email with a reset token:",[332,856,858],{"className":334,"code":857,"language":336,"meta":5,"style":5},"mutation {\n  security {\n    login {\n      forgotPassword(identifier: \"user@example.com\")\n    }\n  }\n}\n",[338,859,860,864,868,872,877,881,885],{"__ignoreMap":5},[341,861,862],{"class":343,"line":344},[341,863,347],{},[341,865,866],{"class":343,"line":350},[341,867,353],{},[341,869,870],{"class":343,"line":356},[341,871,359],{},[341,873,874],{"class":343,"line":362},[341,875,876],{},"      forgotPassword(identifier: \"user@example.com\")\n",[341,878,879],{"class":343,"line":368},[341,880,395],{},[341,882,883],{"class":343,"line":374},[341,884,401],{},[341,886,887],{"class":343,"line":380},[341,888,407],{},[225,890,891,894,895],{},[214,892,893],{},"Reset password"," — uses the token from the email to set a new password:",[332,896,898],{"className":334,"code":897,"language":336,"meta":5,"style":5},"mutation {\n  security {\n    login {\n      resetPassword(token: \"...\", password: \"newSecret\")\n    }\n  }\n}\n",[338,899,900,904,908,912,917,921,925],{"__ignoreMap":5},[341,901,902],{"class":343,"line":344},[341,903,347],{},[341,905,906],{"class":343,"line":350},[341,907,353],{},[341,909,910],{"class":343,"line":356},[341,911,359],{},[341,913,914],{"class":343,"line":362},[341,915,916],{},"      resetPassword(token: \"...\", password: \"newSecret\")\n",[341,918,919],{"class":343,"line":368},[341,920,395],{},[341,922,923],{"class":343,"line":374},[341,924,401],{},[341,926,927],{"class":343,"line":380},[341,928,407],{},[201,930,932],{"id":931},"principal-management","Principal Management",[186,934,935],{},"Authenticated users can manage their own identity:",[222,937,938,953,968],{},[225,939,940,943,944],{},[214,941,942],{},"Change password"," — requires the old password for verification:\n",[332,945,947],{"className":334,"code":946,"language":336,"meta":5,"style":5},"mutation { security { principal { password(oldPassword: \"old\", newPassword: \"new\") } } }\n",[338,948,949],{"__ignoreMap":5},[341,950,951],{"class":343,"line":344},[341,952,946],{},[225,954,955,958,959],{},[214,956,957],{},"Change identifier"," — update the login identifier (email):\n",[332,960,962],{"className":334,"code":961,"language":336,"meta":5,"style":5},"mutation { security { principal { identifier(identifier: \"new@example.com\", password: \"current\") } } }\n",[338,963,964],{"__ignoreMap":5},[341,965,966],{"class":343,"line":344},[341,967,961],{},[225,969,970,973,974],{},[214,971,972],{},"Set primary profile"," — choose which profile is the default:\n",[332,975,977],{"className":334,"code":976,"language":336,"meta":5,"style":5},"mutation { security { principal { setPrimaryProfile(profileId: \"...\") } } }\n",[338,978,979],{"__ignoreMap":5},[341,980,981],{"class":343,"line":344},[341,982,976],{},[186,984,985],{},"Administrators can also manage other principals:",[222,987,988,991,994],{},[225,989,990],{},"Add or remove group memberships",[225,992,993],{},"List and search principals",[225,995,996],{},"Expire all refresh tokens system-wide",[201,998,1000],{"id":999},"how-it-fits-together","How It Fits Together",[222,1002,1003,1011,1018,1026],{},[225,1004,1005,1007,1008,1010],{},[214,1006,70],{},": Every principal can have one or more ",[190,1009,70],{"href":71}," for personalization and display.",[225,1012,1013,1015,1016,525],{},[214,1014,74],{},": Signup tokens and email-domain auto-join integrate identity with ",[190,1017,74],{"href":75},[225,1019,1020,1022,1023,1025],{},[214,1021,198],{},": Verification emails and password-reset emails are sent through the ",[190,1024,198],{"href":118}," layer.",[225,1027,1028,1030,1031,1033],{},[214,1029,138],{},": Identity management builds on top of the ",[190,1032,138],{"href":139}," group and permission model.",[201,1035,1037],{"id":1036},"for-developers","For Developers",[186,1039,1040],{},"The identity system is implemented across two modules:",[222,1042,1043,1058],{},[225,1044,1045,1048,1049,473,1052,473,1055,483],{},[338,1046,1047],{},"backend\u002Fframework\u002Fcore-security"," — interfaces (",[338,1050,1051],{},"SecurityService",[338,1053,1054],{},"PasswordEncoder",[338,1056,1057],{},"ThirdPartyUser",[225,1059,1060,1063],{},[338,1061,1062],{},"backend\u002Fframework\u002Fsecurity"," — implementations (Argon2\u002FScrypt encoding, OAuth2 routes, GraphQL controllers, email templates)",[186,1065,1066],{},"Key extension points:",[222,1068,1069,1085,1095],{},[225,1070,1071,1074,1075,1078,1079,1081,1082,1084],{},[214,1072,1073],{},"Add an OAuth2 provider",": Add a new entry to the ",[338,1076,1077],{},"oauth2.providers"," list in configuration and, if the provider's user-info response differs from the standard OIDC format, create a new ",[338,1080,1057],{}," adapter (see ",[338,1083,492],{}," for an example).",[225,1086,1087,1090,1091,1094],{},[214,1088,1089],{},"Custom email templates",": Implement ",[338,1092,1093],{},"EmailTemplate"," to provide custom HTML\u002Ftext content for verification or password-reset emails.",[225,1096,1097,1090,1100,1103],{},[214,1098,1099],{},"Custom password encoding",[338,1101,1102],{},"PasswordEncoder\u003CT>"," for alternative hashing strategies.",[1105,1106,1107],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":5,"searchDepth":350,"depth":350,"links":1109},[1110,1115,1121,1125,1126,1127,1128],{"id":203,"depth":350,"text":204,"children":1111},[1112,1113,1114],{"id":208,"depth":356,"text":209},{"id":254,"depth":356,"text":255},{"id":284,"depth":356,"text":285},{"id":319,"depth":350,"text":320,"children":1116},[1117,1118,1119,1120],{"id":326,"depth":356,"text":327},{"id":410,"depth":356,"text":411},{"id":528,"depth":356,"text":529},{"id":584,"depth":356,"text":585},{"id":631,"depth":350,"text":632,"children":1122},[1123,1124],{"id":635,"depth":356,"text":636},{"id":758,"depth":356,"text":759},{"id":839,"depth":350,"text":840},{"id":931,"depth":350,"text":932},{"id":999,"depth":350,"text":1000},{"id":1036,"depth":350,"text":1037},"Authentication, signup, credential management, and session handling in Bosca.","md",{},true,{"title":101,"description":1129},"5x9n8rYtbhNmA2OtsgLfzDk7_pj_GtjITRajVMwxiA8",[1136,1138],{"title":96,"path":97,"stem":98,"description":1137,"children":-1},"The Bosca Framework is composed of a rich set of modules, primarily split between the backend and general framework libraries. Each domain follows a pattern of a core-* module (interfaces and models) paired with an implementation module.",{"title":105,"path":106,"stem":107,"description":1139,"children":-1},"Multi-language support for content and interfaces using IETF language tags.",1775372112834]