@sapec/tenalanding-sso 0.3.0

Browser half of the TenaLanding hand-off: read the one-time code out of the URL fragment and exchange it for your application's own tokens.
This is a new version of the view package page, introduced in ProGet 5.3. If it's missing any functionality, you can still view the old version.

Metadata

License UNLICENSED
Downloads 1
Published 9/7/2026 10:11:58 AM

Readme

# @sapec/tenalanding-sso The browser half of the **TenaLanding** hand-off. Two functions, no framework dependency, no `node_modules` of its own — it works in Angular 21, Angular 22, React, or plain TypeScript. The backend half is the NuGet package `TenaLanding.Integration.AspNetCore`, which raises `POST {prefix}/sso` in your application. --- ## Install ```jsonc // package.json "dependencies": { "@sapec/tenalanding-sso": "file:../../.nuget-local/sapec-tenalanding-sso-0.2.0.tgz" } ``` --- ## Use The portal redirects the browser to `{yourPortalUrl}{ssoCallbackPath}#code=…`. The code travels in the **fragment**, so it never reaches a server log or a `Referer` header. Your callback route reads it and hands it to your own backend, which exchanges it server-to-server and answers with your own tokens. ```ts import { readLandingCode, redeemLandingCode, LandingSsoError } from '@sapec/tenalanding-sso'; const code = readLandingCode(); // also wipes it from the browser history if (code) { const auth = await redeemLandingCode<AuthResponse>('/api/landing/sso', code); // auth is exactly what your own /auth/login returns — store it the way you already do } ``` Angular, in full: ```ts @Component({ selector: 'app-landing-sso', templateUrl: './landing-sso.component.html' }) export class LandingSsoComponent implements OnInit { private readonly auth = inject(AuthService); protected readonly failed = signal(false); async ngOnInit(): Promise<void> { const code = readLandingCode(); if (!code) { this.failed.set(true); return; } try { await this.auth.signInWithLandingCode(code); } catch { this.failed.set(true); } } } ``` **Never retry a failed redemption.** The code is single-use and lives 60 seconds; a retry is guaranteed to fail and only muddies the audit trail. Show the message and a link to your normal sign-in page. --- ## API ### `readLandingCode(source?): string | null` Reads `code` out of `location.hash` and immediately replaces the history entry with the same page minus the fragment, so a refresh or a shared URL cannot carry the credential. Returns `null` when there is no code — including when the page was opened directly rather than through the portal. `source` is only for tests; it defaults to `window`. ### `redeemLandingCode<T>(redeemUrl, code, init?): Promise<T>` `POST`s `{ "code": "…" }` as JSON and returns the parsed body — **your** application's auth response, unchanged, because the backend package serializes whatever your `ILandingSignIn<T>` returned. Throws `LandingSsoError` on a non-2xx answer, carrying `status` and the `detail` (or `title`) of the RFC 7807 problem document your application returned, so the message you show the person is the one your backend chose. `init` is merged into the `fetch` call — use it for `credentials`, an `AbortSignal`, or extra headers.