Implement the jsConnect V3 Protocol - HL Vanilla Community
<main> <article class="userContent"> <p><strong>Higher Logic Vanilla (Vanilla)</strong> offers several client libraries that you can use on your site if you're implementing jsConnect. If your site is programmed in a different language or you can't use one of Vanilla's libraries, this article explains how to implement the protocol.</p><h2 data-id="what-you'll-need">What you'll need</h2><p>To implement jsConnect, you'll need to create an authentication page on your site that gives details of the currently signed in user. The jsConnect v3 protocol uses <a href="https://jwt.io/" rel="nofollow noreferrer ugc">JSON Web Tokens (JWT)</a> to secure the SSO. </p><p><strong>✔️ TIP</strong>: We highly recommend using an existing JWT library to verify and create JWTs. </p><p>Vanilla uses the <strong>HMAC SHA256</strong> algorithm to sign tokens, so you need to have a library that can implement that hash algorithm at a minimum.</p><h2 data-id="authentication-workflow">Authentication workflow</h2><p>Here's an example of a typical log in workflow using jsConnect v3:</p><ol><li>A user clicks the <strong>Sign In </strong>link in your Vanilla community, which points to our <code class="code codeInline" spellcheck="false" tabindex="0">jsconnect-redirect</code> endpoint with:<ol><li>The <code class="code codeInline" spellcheck="false" tabindex="0">client_id</code> of the jsConnect application you entered in the Vanilla Dashboard and </li><li>The <code class="code codeInline" spellcheck="false" tabindex="0">Target</code> value, which is the path of the current page.</li></ol></li><li><code class="code codeInline" spellcheck="false" tabindex="0">jsconntect-redirect</code> generates State data and the Return URL, and compiles it into a JWT. The payload of the state includes the:<ol><li> Target (e.g., `"t" : "/discussions"`) and,</li><li>The "nonce," a random hash that is returned to us to confirm integrity of the communication (e.g., `"n" : "MXet9yoFxkVvzUCpzICj"`)</li></ol></li><li> The user is redirected back to Return URL, which was passed in the JWT (e.g., `rurl : "https://myforums.com/entry/jsconnect"`) with the JWT response in the URL fragment (see <a href="https://success.vanillaforums.com/kb/articles/211-implementing-the-jsconnect-version-3-protocol#redirect-back-to-vanilla-with-your-response" rel="nofollow noreferrer ugc">Redirect back to Vanilla with your response</a> below).</li><li>Your system generates a JWT response (see <a href="https://success.vanillaforums.com/kb/articles/211-implementing-the-jsconnect-version-3-protocol#generate-a-jwt-with-your-response" rel="nofollow noreferrer ugc">Generate a JWT with your response</a> below).</li><li>The user logs in on your system or your system detects that user already has an authenticated session on your system.</li><li>User is then 302-redirected to the Sign In URL you configured in your Vanilla Dashboard with the <code class="code codeInline" spellcheck="false" tabindex="0">jwt</code> as a GET parameter (e.g., https://myssite.com/signin?jwt=eyJraWQiOiJzdHViX...bqP0lI).</li></ol><h2 data-id="authentication-page-process">Authentication page process</h2><p>Your authentication page will do the following:</p><ol><li>Verify the jsConnect request from Vanilla.</li><li>Generate a JWT with your response and the current user's information.</li><li>Redirect back to Vanilla with your response.</li></ol><h3 data-id="verify-the-jsconnect-request-from-vanilla">Verify the jsConnect request from Vanilla</h3><p>Vanilla sends its request in the querystring under the <code class="code codeInline" spellcheck="false" tabindex="0">jwt</code> parameter. The value of the parameter is a JWT, and you need to verify it with the following process:</p><ol><li>Verify the JWT with your library. The secret is the one you configured in Vanilla under the jsConnect connection.</li><li>Make sure the JWT has an <code class="code codeInline" spellcheck="false" tabindex="0">rurl</code> claim. This claim is the URL that you need to redirect back to.</li></ol><h3 data-id="generate-a-jwt-with-your-response">Generate a JWT with your response</h3><p>Your response should have the following fields:</p><pre class="code codeBlock" spellcheck="false" tabindex="0">// header { "kid": "jsConnect client ID" } // payload { "v": "lang:1.0", // version information "iat": 1586349451, // current unix timestamp "exp": 1586350051, // expiry, no more than 10 minutes from now "u": {}, // your user or an empty object if not signed in "st": {}, // this is the "st" field from the request } </pre><h4 data-id="the-user-field">The User field</h4><p>Your user information goes in the <code class="code codeInline" spellcheck="false" tabindex="0">u</code> field of your JWT's payload. It can contain the following standard fields:</p><pre class="code codeBlock" spellcheck="false" tabindex="0">{ "id": "12345", // database ID that identifies your user "name": "username", // username of your user "email": "user@example.com", // email address "photoUrl": "https://example.com/avatar.jpg", // avatar "roles": [] // array of role names or IDs } </pre><ul><li>Only the <code class="code codeInline" spellcheck="false" tabindex="0">id</code> field is required, but you typically want to pass some or all of the other fields.</li><li>If there is no user signed into your system, just put an empty object in the user field.</li></ul><h4 data-id="the-state-field">The State field</h4><p>The state goes in the <code class="code codeInline" spellcheck="false" tabindex="0">st</code> field of your JWT's payload. This field comes from the request, and is necessary to secure the SSO.</p><h4 data-id="the-version-field">The Version field</h4><p>The version goes in the <code class="code codeInline" spellcheck="false" tabindex="0">v</code> field of your JWT's payload. We like to use the convention <code class="code codeInline" spellcheck="false" tabindex="0">language:version</code> for this field to give both the language the library was written in and its specific version number. Adding a version greatly helps with troubleshooting, so we highly recommend you add it.</p><h3 data-id="redirect-back-to-vanilla-with-your-response">Redirect back to Vanilla with your response</h3><p>Once you've verified the request and generated your response token, you need to 302-redirect back to Vanilla. Your redirect URL takes the following format:</p><pre class="code codeBlock" spellcheck="false" tabindex="0"><redirect url>#jwt=<response jwt> </pre><ul><li>For the redirect URL, you need to use the <code class="code codeInline" spellcheck="false" tabindex="0">rurl</code> that came in the payload from the request. Do not hard code this URL, as it may change in the future.</li><li>For the response JWT, you use the JWT that you generated in step 2 above.</li></ul><p><strong>📝 NOTE</strong>: For the response, the JWT is transmitted in the fragment rather than the querystring. This is to provide another layer of security so that specific authentication tokens don't show up in server logs.</p><h2 data-id="troubleshooting-and-tips">Troubleshooting and tips</h2><p>Here are a few tips for troubleshooting your jsConnect integration. The first step to troubleshooting your connection is to use the Test feature in the <a href="https://success.vanillaforums.com/kb/articles/206-upgrading-jsconnect-to-version-3#test-your-connection" rel="nofollow noreferrer ugc"> jsConnect Addon in the Dashboard</a>.</p><h3 data-id="validate-your-jwt-response">Validate your JWT response</h3><p>When you test your jsConnect connection in the Dashboard, you can retrieve the JWT response you're sending and test it by pasting it in the "Encoded" field at <a href="https://jwt.io/" rel="nofollow noreferrer ugc">jwt.io</a></p><div class="embedExternal embedImage display-large float-none"> <div class="embedExternal-content"> <a class="embedImage-link" href="https://us.v-cdn.net/6030677/uploads/693/Screen%20Shot%202020-05-11%20at%205.15.13%20PM.png" rel="nofollow noreferrer noopener ugc" target="_blank"> <img class="embedImage-img" src="https://us.v-cdn.net/6030677/uploads/693/Screen%20Shot%202020-05-11%20at%205.15.13%20PM.png" alt="Screen Shot 2020-05-11 at 5.15.13 PM.png" height="180" width="320" loading="lazy" data-display-size="large" data-float="none"></img></a> </div> </div> <h3 data-id="%22nonce-not-found%22">"Nonce not Found"</h3><p>If you receive a "Nonce not Found" error message when trying to connect to the community, <a href="https://success.vanillaforums.com/kb/articles/206/editor#validate-your-jwt-response" rel="nofollow noreferrer ugc">verify your response token</a>. If you're not using one of our libraries to generate your jsConnect response you may be using a library that handles the State value differently. The state (`st`) in the payload of your response to Vanilla needs to return the same 'nonce' (`n`) that Vanilla sent to you:</p><pre class="code codeBlock" spellcheck="false" tabindex="0">{ "u": { "id": "457", "name": "User", "email": "user@example.com", "roles": "Expert" }, "st": { "n": "FNWewhMzGuPeyrY_xStY" }, "v": "php:3", "iat": 1589231685, "exp": 1589232285 } </pre><h3 data-id="token-expired">Token Expired</h3><p>If you receive a jsConnect request with an expired JWT token (<code class="code codeInline" spellcheck="false" tabindex="0">exp</code> < now()) or no nonce (<code class="code codeInline" spellcheck="false" tabindex="0">n</code> ) output an error instructing the user to log in again. Do not redirect them back to your site automatically, as this could cause a loop in some cases.</p><h3 data-id="user-does-not-exist">User Does Not Exist</h3><p>If someone initiates a login with jsConnect but the user does not exist or fails to log in, you can send them back to the community flagged as a guest by invoking the <code class="code codeInline" spellcheck="false" tabindex="0">setGuest()</code> method that should exist in your jsConnect library. In PHP this would be: <code class="code codeInline" spellcheck="false" tabindex="0">JsConnect::setGuest()</code>.</p><h2 data-id="reference-implementation">Reference implementation</h2><p>This article explains how to <em>implement jsConnect v3</em>. If you learn better by reading code, we recommend you reference our <a href="https://github.com/vanilla/jsConnectPHP/blob/master/src/JsConnect.php" rel="nofollow noreferrer ugc">PHP implementation</a>.</p> </article> </main>