--- title: "Implement JWT in your application" slug: "implement-jwt-in-your-application" description: "Implement backend authentication for Document360 with C#, Node.js, or Java. Ensure secure login flow and proper redirection to your knowledge base." updated: 2026-06-19T12:11:02Z published: 2026-06-19T12:11:02Z canonical: "docs.document360.com/implement-jwt-in-your-application" --- > ## Documentation Index > Fetch the complete documentation index at: https://docs.document360.com/llms.txt > Use this file to discover all available pages before exploring further. # Implement JWT in your application After completing the JWT configuration in Document360, your application needs a backend route to handle the final step of the login flow. This route: - Validates that the user is already authenticated in your application - Sends a secure request to Document360's Code generation URL - Retrieves a one-time authorization code - Redirects the user to the knowledge base site with that code :::(Info) (

NOTE) Readers do not require a separate Document360 account. Authentication is handled entirely through your application. An account in your application is sufficient for a reader to access the knowledge base. ::: --- ## Code samples The examples below show how to implement the backend authentication route in C#, Node.js, and Java. ### C\# ```csharp /// /// Example endpoint to authenticate a user and retrieve a token from the identity server, /// and redirect the user to the Knowledge Base (KB) using the token code. /// /// Client ID issued for your application /// Client secret associated with the client ID /// Redirects to the KB with the issued code [HttpGet] [Route("authenticate")] public async Task AuthenticateAsync(string clientId, string clientSecret) { if (!HttpContext.User.Identity.IsAuthenticated) { // user is not authenticated, redirect to an error or login page return Unauthorized(new { message = "User not authenticated" }); } // Ensure you have the correct client ID and secret from your Document360 JWT configuration var authToken = Encoding.ASCII.GetBytes($"{clientId}:{clientSecret}"); // Create an HttpClient instance using var httpClient = new HttpClient(); // Set the Authorization header with Basic authentication httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(authToken)); // Prepare the payload with user information var payload = new { username = User.Identity.Name, firstName = "FirstName", // Replace or customize as needed lastName = "LastName", emailId = "user@example.com", // Replace with actual user email readerGroupIds = new List { "group1", "group2" }, // Replace with actual reader group IDs if needed (Optional) tokenValidity = 3600 // Token validity in seconds (Optional, default is 5 minutes) }; var payloadContent = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"); // Identity server token endpoint - replace with your actual URL string identityServerUrl = "codeGeneration endpoint, you can find that in JWT config portal"; // KB login URL to redirect after successful token issuance string kbLoginUrl = "https://{your subdomain}.document360.io"; var response = await httpClient.PostAsync(identityServerUrl, payloadContent); if (response.IsSuccessStatusCode) { var content = await response.Content.ReadAsStringAsync(); var tokenJson = JObject.Parse(content); // Extract the code from the response var tokenCode = (string)tokenJson.SelectToken("code"); // Construct the KB login URL with code query parameter string finalRedirectUrl = $"{kbLoginUrl}?code={tokenCode}"; return Redirect(finalRedirectUrl); } else { // Handle error response from the identity server var error = await response.Content.ReadAsStringAsync(); return StatusCode((int)response.StatusCode, new { error = "Token request failed", details = error }); } } ``` ### Node.js ```javascript const express = require('express'); const https = require('https'); const axios = require('axios'); const app = express(); app.use(express.json()); const clientId = 'your-client-id'; const clientSecret = 'your-client-secret'; const codeGenerationUrl = 'https://identity.document360.net/jwt/generateCode'; const kbLoginUrl = 'https://your-subdomain.document360.net/jwt/authorize'; app.get('/authenticate', async (req, res) => { try { const isAuthenticated = true; // Replace with your actual auth logic if (!isAuthenticated) { return res.status(401).json({ message: 'User not authenticated' }); } const authHeader = Buffer.from(`${clientId}:${clientSecret}`).toString('base64'); const payload = { username: 'john.doe', firstName: 'John', lastName: 'Doe', emailId: 'john.doe@example.com', readerGroupIds: ['group1', 'group2'], tokenValidity: 3600 }; const response = await axios.post( codeGenerationUrl, payload, { headers: { 'Authorization': `Basic ${authHeader}`, 'Content-Type': 'application/json', 'Accept': 'application/json' }, httpsAgent: new https.Agent({ maxVersion: 'TLSv1.2' }) } ); const tokenCode = response.data?.code; if (!tokenCode) { return res.status(500).json({ message: 'No code received from Document360' }); } console.log("Redirecting to:", `${kbLoginUrl}?code=${tokenCode}`); return res.redirect(`${kbLoginUrl}?code=${tokenCode}`); } catch (error) { return res.status(500).json({ message: 'JWT SSO failed', details: error.response?.data || error.message }); } }); ``` ### Java ```java import org.springframework.http.*; import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; import java.nio.charset.StandardCharsets; import java.util.*; @RestController public class JwtSsoController { private final String clientId = "your-client-id"; private final String clientSecret = "your-client-secret"; private final String codeGenerationUrl = "https://identity.document360.io/api/jwt/generate-code"; private final String kbLoginUrl = "https://your-subdomain.document360.io/jwt/authorize"; @GetMapping("/authenticate") public ResponseEntity authenticate() { // Example: Check if user is authenticated in your system boolean isAuthenticated = true; // Replace with actual logic if (!isAuthenticated) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("User not authenticated"); } // Create Basic Auth header String auth = clientId + ":" + clientSecret; String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8)); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.set("Authorization", "Basic " + encodedAuth); headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); // Construct payload Map payload = new HashMap<>(); payload.put("username", "john.doe"); payload.put("firstName", "John"); payload.put("lastName", "Doe"); payload.put("emailId", "john.doe@example.com"); payload.put("readerGroupIds", Arrays.asList("group1", "group2")); payload.put("tokenValidity", 3600); HttpEntity> request = new HttpEntity<>(payload, headers); RestTemplate restTemplate = new RestTemplate(); try { ResponseEntity response = restTemplate.postForEntity(codeGenerationUrl, request, Map.class); if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) { String tokenCode = (String) response.getBody().get("code"); if (tokenCode == null || tokenCode.isEmpty()) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("No code returned from Document360"); } // Redirect to the KB site with code String redirectUrl = UriComponentsBuilder.fromHttpUrl(kbLoginUrl) .queryParam("code", tokenCode) .toUriString(); HttpHeaders redirectHeaders = new HttpHeaders(); redirectHeaders.setLocation(java.net.URI.create(redirectUrl)); return new ResponseEntity<>(redirectHeaders, HttpStatus.FOUND); } else { return ResponseEntity.status(HttpStatus.BAD_GATEWAY) .body("Failed to get code from Document360: " + response.getStatusCode()); } } catch (Exception ex) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("JWT SSO error: " + ex.getMessage()); } } } ``` --- ## Developer checklist Before going live, verify the following: - [ ] Register the Login URL, Callback URL, and Code generation URL in your JWT settings. - [ ] Store the Client Secret securely. It is displayed only once at the time of creation. - [ ] Implement backend logic to call the Code generation URL using HTTP Basic Auth. - [ ] Sign the JWT in your backend using your client secret. Never expose signing logic on the client side. - [ ] Enforce HTTPS on all endpoints involved in the authentication flow. - [ ] Test session behavior, token expiry, and automatic session renewal before going live. - [ ] Monitor backend logs for 401 errors, which typically indicate expired authorization codes or token mismatches. --- ## Redirecting to a specific page after login By default, after logging in, readers are redirected to the **Home page** of your knowledge base. - If your Home page is unpublished, readers are redirected to the `/docs` page. - To redirect readers to a different page in your knowledge base, configure the redirection using the following URL pattern. **URL pattern** ``` https:///jwt/authorize?code=&redirectUrl= ``` **Parameters** - ``: the main URL of your knowledge base site. - ``: the code generated by the Document360 code generation endpoint. - ``: the URL where you want readers to land after login. **Example** ``` https://example.document360.io/jwt/authorize?code=FOTaS_SW6dLGytQXvrG_rRFGhyPvrDDrgxJAZzYvJcY&redirectUrl=/docs/5-basic-things-to-get-started ``` :::(Info) (

NOTE) Document360 will send the Redirection URL as `redirectPath` to the login endpoint. When the login endpoint redirects back to the knowledge base with the authentication code, it should return the Redirection URL as a `redirectUrl` parameter. In **KB Site 2.0**, redirection is handled using cookies instead of the `redirectUrl` parameter. If your JWT implementation is based on query string redirection using the `redirectUrl` parameter, the cookie-based approach does not support this parameter. You may need to update your implementation or [contact support](mailto:support@document360.com) for further clarification. :::