diff --git a/e2e/dpop/.env.example b/e2e/dpop/.env.example new file mode 100644 index 0000000..0174bd1 --- /dev/null +++ b/e2e/dpop/.env.example @@ -0,0 +1,11 @@ +# Public OAuth client identifiers; these are not secrets. +REACT_CLIENT_ID=replace-with-react-client-id +VUE_CLIENT_ID=replace-with-vue-client-id +ANGULAR_CLIENT_ID=replace-with-angular-client-id + +# The current FusionAuth tenant issuer. +EXPECTED_ISSUER=https://example.com +FUSIONAUTH_JWKS_URL=http://host.orb.internal:9011/.well-known/jwks.json + +# Canonical public origin used for DPoP htu validation. +API_EXTERNAL_ORIGIN=https://api.fusionauth-dpop.orb.local diff --git a/e2e/dpop/.gitignore b/e2e/dpop/.gitignore new file mode 100644 index 0000000..30bd623 --- /dev/null +++ b/e2e/dpop/.gitignore @@ -0,0 +1,2 @@ +.env + diff --git a/e2e/dpop/README.md b/e2e/dpop/README.md new file mode 100644 index 0000000..af22aba --- /dev/null +++ b/e2e/dpop/README.md @@ -0,0 +1,46 @@ +# Manual DPoP browser demo + +This fixture builds the React, Vue, and Angular SDKs from this checkout, then +serves three minimal browser apps and one DPoP-protected Express API through +OrbStack. OrbStack terminates TLS. + +## Configure and start + +Prerequisites: OrbStack with Docker Compose, and FusionAuth available at +`https://local.fusionauth.io`. + +Create three public FusionAuth applications with Authorization Code and Refresh +Token grants, client authentication disabled, PKCE required with S256, and +asymmetric access-token signing. Use each app URL below as its exact authorized +redirect and logout URL. Add all three origins to FusionAuth CORS and allow the +`Authorization`, `Content-Type`, and `DPoP` headers with `GET`, `POST`, and +`OPTIONS` methods. + +```bash +cd e2e/dpop +cp .env.example .env +# Edit .env with the three public client IDs. +docker compose build +docker compose up -d +docker compose ps +``` + +Open: + +- https://react.fusionauth-dpop.orb.local +- https://vue.fusionauth-dpop.orb.local +- https://angular.fusionauth-dpop.orb.local +- https://api.fusionauth-dpop.orb.local/health + +In each app, click **Login**, authenticate, click **Call resource server**, and +confirm the protected response. Click **Logout** to finish. + +Stop the fixture with: + +```bash +docker compose down +``` + +The `.env` values are public identifiers, but `.env` is local configuration and +must not contain secrets. + diff --git a/e2e/dpop/angular/Dockerfile b/e2e/dpop/angular/Dockerfile new file mode 100644 index 0000000..0b3b100 --- /dev/null +++ b/e2e/dpop/angular/Dockerfile @@ -0,0 +1,24 @@ +FROM node:24.15.0-alpine AS sdk-build +WORKDIR /repo +ENV HUSKY=0 +COPY package.json yarn.lock tsconfig.json ./ +COPY packages ./packages +RUN corepack enable && corepack prepare yarn@1.22.22 --activate +RUN yarn install --frozen-lockfile --ignore-engines --non-interactive +RUN yarn build:sdk-angular + +FROM node:24.15.0-alpine AS app-build +WORKDIR /app +ARG CLIENT_ID +RUN corepack enable && corepack prepare yarn@1.22.22 --activate +COPY e2e/dpop/angular/package.json ./ +COPY --from=sdk-build /repo/packages/sdk-angular/dist/fusionauth-angular-sdk ./vendor/angular-sdk +RUN yarn install --non-interactive +COPY e2e/dpop/angular/angular.json e2e/dpop/angular/tsconfig.json ./ +COPY e2e/dpop/angular/src ./src +RUN test -n "$CLIENT_ID" && sed -i "s|__CLIENT_ID__|$CLIENT_ID|" src/main.ts +RUN yarn build + +FROM nginx:1.29-alpine +COPY e2e/dpop/nginx.conf /etc/nginx/conf.d/default.conf +COPY --from=app-build /app/dist/angular/browser /usr/share/nginx/html diff --git a/e2e/dpop/angular/angular.json b/e2e/dpop/angular/angular.json new file mode 100644 index 0000000..d149d4e --- /dev/null +++ b/e2e/dpop/angular/angular.json @@ -0,0 +1,28 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "angular": { + "projectType": "application", + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular/build:application", + "options": { + "browser": "src/main.ts", + "index": "src/index.html", + "outputPath": "dist/angular", + "polyfills": ["zone.js"], + "tsConfig": "tsconfig.json" + } + } + } + } + }, + "cli": { + "analytics": false + } +} diff --git a/e2e/dpop/angular/package.json b/e2e/dpop/angular/package.json new file mode 100644 index 0000000..65966de --- /dev/null +++ b/e2e/dpop/angular/package.json @@ -0,0 +1,24 @@ +{ + "name": "dpop-angular-demo", + "private": true, + "version": "0.0.0", + "scripts": { + "build": "ng build" + }, + "dependencies": { + "@angular/common": "22.0.0", + "@angular/compiler": "22.0.0", + "@angular/core": "22.0.0", + "@angular/platform-browser": "22.0.0", + "@fusionauth/angular-sdk": "file:vendor/angular-sdk", + "rxjs": "7.8.2", + "tslib": "2.8.1", + "zone.js": "0.15.1" + }, + "devDependencies": { + "@angular/build": "22.0.0", + "@angular/cli": "22.0.0", + "@angular/compiler-cli": "22.0.0", + "typescript": "6.0.2" + } +} diff --git a/e2e/dpop/angular/src/index.html b/e2e/dpop/angular/src/index.html new file mode 100644 index 0000000..c65dc4c --- /dev/null +++ b/e2e/dpop/angular/src/index.html @@ -0,0 +1,12 @@ + + + + + + Angular DPoP demo + + + + + + diff --git a/e2e/dpop/angular/src/main.ts b/e2e/dpop/angular/src/main.ts new file mode 100644 index 0000000..35678c2 --- /dev/null +++ b/e2e/dpop/angular/src/main.ts @@ -0,0 +1,53 @@ +import { Component, inject } from '@angular/core'; +import { bootstrapApplication } from '@angular/platform-browser'; +import { FusionAuthModule, FusionAuthService } from '@fusionauth/angular-sdk'; + +const apiUrl = 'https://api.fusionauth-dpop.orb.local/resource'; +const appUrl = 'https://angular.fusionauth-dpop.orb.local'; + +@Component({ + imports: [FusionAuthModule], + selector: 'app-root', + standalone: true, + template: ` +
+

Angular DPoP demo

+ @if (fusionAuth.isLoggedInSignal()) { + + + } @else { + + } +
{{ result }}
+
+ `, +}) +class AppComponent { + readonly fusionAuth = inject(FusionAuthService); + result = ''; + + async callResource() { + try { + const response = await this.fusionAuth.dpopFetch(apiUrl); + const body = await response.text(); + this.result = response.ok ? body : `HTTP ${response.status}: ${body}`; + } catch (error) { + this.result = error instanceof Error ? error.message : 'Request failed'; + } + } +} + +bootstrapApplication(AppComponent, { + providers: [ + ...FusionAuthModule.forRoot({ + clientId: '__CLIENT_ID__', + dpopTokenStorage: 'localStorage', + postLogoutRedirectUri: appUrl, + redirectUri: appUrl, + serverUrl: 'https://local.fusionauth.io', + useDpop: true, + }).providers!, + ], +}).catch(() => { + document.body.textContent = 'Application failed to start'; +}); diff --git a/e2e/dpop/angular/tsconfig.json b/e2e/dpop/angular/tsconfig.json new file mode 100644 index 0000000..35b4a7d --- /dev/null +++ b/e2e/dpop/angular/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "experimentalDecorators": true, + "lib": ["ES2022", "DOM"], + "module": "preserve", + "moduleResolution": "bundler", + "strict": true, + "target": "ES2022" + }, + "angularCompilerOptions": { + "strictTemplates": true + }, + "files": ["src/main.ts"] +} diff --git a/e2e/dpop/api/Dockerfile b/e2e/dpop/api/Dockerfile new file mode 100644 index 0000000..0f60707 --- /dev/null +++ b/e2e/dpop/api/Dockerfile @@ -0,0 +1,11 @@ +FROM node:24.15.0-alpine +WORKDIR /app +ENV NODE_ENV=production +RUN corepack enable && corepack prepare yarn@1.22.22 --activate +COPY e2e/dpop/api/package.json ./ +RUN yarn install --production --non-interactive +COPY e2e/dpop/api/server.mjs ./ +USER node +EXPOSE 3000 +CMD ["node", "server.mjs"] + diff --git a/e2e/dpop/api/package.json b/e2e/dpop/api/package.json new file mode 100644 index 0000000..124aad7 --- /dev/null +++ b/e2e/dpop/api/package.json @@ -0,0 +1,11 @@ +{ + "name": "dpop-resource-server", + "private": true, + "version": "0.0.0", + "type": "module", + "dependencies": { + "cors": "2.8.5", + "express": "5.1.0", + "jose": "6.1.0" + } +} diff --git a/e2e/dpop/api/server.mjs b/e2e/dpop/api/server.mjs new file mode 100644 index 0000000..5ddef2c --- /dev/null +++ b/e2e/dpop/api/server.mjs @@ -0,0 +1,300 @@ +import { Buffer } from 'node:buffer'; +import console from 'node:console'; +import { createHash, timingSafeEqual } from 'node:crypto'; +import process from 'node:process'; +import cors from 'cors'; +import express from 'express'; +import { + calculateJwkThumbprint, + createRemoteJWKSet, + decodeProtectedHeader, + importJWK, + jwtVerify, +} from 'jose'; + +const port = 3000; +const proofMaxAgeSeconds = 300; +const replayCacheLimit = 10_000; +const configuredApiOrigin = new URL( + process.env.API_EXTERNAL_ORIGIN ?? 'https://api.fusionauth-dpop.orb.local', +); +if ( + configuredApiOrigin.protocol !== 'https:' || + configuredApiOrigin.pathname !== '/' || + configuredApiOrigin.search || + configuredApiOrigin.hash +) { + throw new Error('API_EXTERNAL_ORIGIN must be an HTTPS origin'); +} +const apiOrigin = configuredApiOrigin.origin; +const issuer = process.env.EXPECTED_ISSUER ?? 'https://example.com'; +const audiences = [ + process.env.REACT_CLIENT_ID, + process.env.VUE_CLIENT_ID, + process.env.ANGULAR_CLIENT_ID, +].filter(Boolean); +const allowedOrigins = [ + 'https://react.fusionauth-dpop.orb.local', + 'https://vue.fusionauth-dpop.orb.local', + 'https://angular.fusionauth-dpop.orb.local', +]; +const jwksUrl = + process.env.FUSIONAUTH_JWKS_URL ?? + 'http://host.orb.internal:9011/.well-known/jwks.json'; +const jwks = createRemoteJWKSet(new URL(jwksUrl)); +const replayCache = new Map(); +let requestSequence = 0; + +function log(requestId, message, value) { + const prefix = `[DPoP request ${requestId}] ${message}`; + if (value === undefined) { + console.log(prefix); + } else { + console.log(prefix, value); + } +} + +function constantTimeEqual(left, right) { + const leftBuffer = Buffer.from(left); + const rightBuffer = Buffer.from(right); + return ( + leftBuffer.length === rightBuffer.length && + timingSafeEqual(leftBuffer, rightBuffer) + ); +} + +function externalRequestUrl(request) { + return `${apiOrigin}${request.path}`; +} + +function rejectReplay(thumbprint, jti, now, requestId) { + log(requestId, 'Replay cache before pruning', { + size: replayCache.size, + thumbprint, + jti, + now, + }); + for (const [key, expiresAt] of replayCache) { + if (expiresAt <= now) { + log(requestId, 'Pruning expired replay entry', { key, expiresAt }); + replayCache.delete(key); + } + } + + const key = `${thumbprint}:${jti}`; + if (replayCache.has(key)) { + log(requestId, 'Replay detected', { key, expiresAt: replayCache.get(key) }); + throw new Error('Replayed proof'); + } + if (replayCache.size >= replayCacheLimit) { + const oldestKey = replayCache.keys().next().value; + log(requestId, 'Replay cache full; evicting oldest entry', oldestKey); + replayCache.delete(oldestKey); + } + replayCache.set(key, now + proofMaxAgeSeconds * 1000); + log(requestId, 'Proof added to replay cache', { + key, + expiresAt: replayCache.get(key), + size: replayCache.size, + }); +} + +async function validateDpop(request, requestId) { + const authorization = request.get('authorization') ?? ''; + const match = authorization.match(/^DPoP ([^\s]+)$/i); + const proof = request.get('dpop'); + log(requestId, 'Incoming request', { + method: request.method, + originalUrl: request.originalUrl, + path: request.path, + protocol: request.protocol, + hostname: request.hostname, + host: request.get('host'), + ip: request.ip, + headers: request.headers, + }); + log(requestId, 'Raw Authorization header', authorization); + log(requestId, 'Raw DPoP proof', proof); + log(requestId, 'Credential parsing', { + authorizationMatched: Boolean(match), + proofPresent: Boolean(proof), + }); + if (!match || !proof) { + throw new Error('Missing credentials'); + } + const accessToken = match[1]; + log(requestId, 'Raw access token', accessToken); + log(requestId, 'Starting access-token JWT verification', { + issuer, + audiences, + }); + + const { payload: tokenPayload } = await jwtVerify(accessToken, jwks, { + audience: audiences, + issuer, + }); + log(requestId, 'Access-token JWT verification succeeded', tokenPayload); + + const proofHeader = decodeProtectedHeader(proof); + log(requestId, 'Decoded DPoP protected header', proofHeader); + log(requestId, 'Proof-header checks', { + typActual: proofHeader.typ, + typExpected: 'dpop+jwt', + algActual: proofHeader.alg, + algExpected: 'ES256', + jwkPresent: Boolean(proofHeader.jwk), + ktyActual: proofHeader.jwk?.kty, + ktyExpected: 'EC', + crvActual: proofHeader.jwk?.crv, + crvExpected: 'P-256', + containsPrivateKey: Boolean(proofHeader.jwk && 'd' in proofHeader.jwk), + }); + if ( + proofHeader.typ?.toLowerCase() !== 'dpop+jwt' || + proofHeader.alg !== 'ES256' || + !proofHeader.jwk || + proofHeader.jwk.kty !== 'EC' || + proofHeader.jwk.crv !== 'P-256' || + 'd' in proofHeader.jwk + ) { + throw new Error('Invalid proof header'); + } + + log(requestId, 'Importing proof public key'); + const proofKey = await importJWK(proofHeader.jwk, 'ES256'); + log(requestId, 'Starting DPoP proof signature verification', { + algorithms: ['ES256'], + clockTolerance: 5, + maxTokenAgeSeconds: proofMaxAgeSeconds, + }); + const { payload: proofPayload } = await jwtVerify(proof, proofKey, { + algorithms: ['ES256'], + clockTolerance: 5, + maxTokenAge: `${proofMaxAgeSeconds} seconds`, + }); + log(requestId, 'DPoP proof signature verification succeeded', proofPayload); + + const nowSeconds = Math.floor(Date.now() / 1000); + const expectedHtu = externalRequestUrl(request); + log(requestId, 'Proof-claim checks', { + htmActual: proofPayload.htm, + htmExpected: request.method, + htmMatches: proofPayload.htm === request.method, + htuActual: proofPayload.htu, + htuExpected: expectedHtu, + htuMatches: proofPayload.htu === expectedHtu, + iatActual: proofPayload.iat, + nowSeconds, + iatAgeSeconds: + typeof proofPayload.iat === 'number' + ? nowSeconds - proofPayload.iat + : undefined, + iatIsInteger: Number.isInteger(proofPayload.iat), + iatWithinMaxAge: + Number.isInteger(proofPayload.iat) && + Math.abs(nowSeconds - proofPayload.iat) <= proofMaxAgeSeconds, + jtiActual: proofPayload.jti, + jtiValid: + typeof proofPayload.jti === 'string' && proofPayload.jti.length > 0, + athActual: proofPayload.ath, + athIsString: typeof proofPayload.ath === 'string', + nonceActual: proofPayload.nonce, + }); + if ( + proofPayload.htm !== request.method || + proofPayload.htu !== expectedHtu || + !Number.isInteger(proofPayload.iat) || + Math.abs(nowSeconds - proofPayload.iat) > proofMaxAgeSeconds || + typeof proofPayload.jti !== 'string' || + proofPayload.jti.length === 0 || + typeof proofPayload.ath !== 'string' + ) { + throw new Error('Invalid proof claims'); + } + + const expectedAth = createHash('sha256') + .update(accessToken) + .digest('base64url'); + log(requestId, 'Access-token hash check', { + athActual: proofPayload.ath, + athExpected: expectedAth, + matches: constantTimeEqual(proofPayload.ath, expectedAth), + }); + if (!constantTimeEqual(proofPayload.ath, expectedAth)) { + throw new Error('Invalid token hash'); + } + + const thumbprint = await calculateJwkThumbprint(proofHeader.jwk, 'sha256'); + log(requestId, 'Token-binding check', { + cnfActual: tokenPayload.cnf, + jktActual: tokenPayload.cnf?.jkt, + proofJwkThumbprintExpected: thumbprint, + matches: + typeof tokenPayload.cnf?.jkt === 'string' && + constantTimeEqual(tokenPayload.cnf.jkt, thumbprint), + }); + if ( + typeof tokenPayload.cnf !== 'object' || + tokenPayload.cnf === null || + typeof tokenPayload.cnf.jkt !== 'string' || + !constantTimeEqual(tokenPayload.cnf.jkt, thumbprint) + ) { + throw new Error('Invalid token binding'); + } + + rejectReplay(thumbprint, proofPayload.jti, Date.now(), requestId); + log(requestId, 'All JWT and DPoP validation checks passed'); +} + +const app = express(); +app.disable('x-powered-by'); +app.use( + cors({ + allowedHeaders: ['Authorization', 'Content-Type', 'DPoP'], + methods: ['GET', 'OPTIONS'], + origin: allowedOrigins, + }), +); + +app.get('/health', (_request, response) => { + response.json({ status: 'ok' }); +}); + +app.get('/resource', async (request, response) => { + const requestId = ++requestSequence; + log(requestId, '----- BEGIN /resource validation -----'); + response.set('Cache-Control', 'no-store'); + try { + await validateDpop(request, requestId); + log(requestId, 'Returning 200 protected resource response'); + response.json({ message: 'DPoP-protected resource reached' }); + } catch (error) { + log(requestId, 'Validation failed', { + name: error?.name, + code: error?.code, + message: error?.message, + stack: error?.stack, + cause: error?.cause, + }); + log(requestId, 'Returning 401 invalid_dpop_request'); + response.status(401).json({ error: 'invalid_dpop_request' }); + } finally { + log(requestId, '----- END /resource validation -----'); + } +}); + +app.listen(port, '0.0.0.0', () => { + console.log(`DPoP resource server listening on port ${port}`); + console.log('DPoP resource server validation configuration', { + apiOrigin, + issuer, + audiences, + allowedOrigins, + jwksUrl, + proofMaxAgeSeconds, + replayCacheLimit, + }); + console.warn( + 'DEV DIAGNOSTICS ENABLED: raw Authorization headers, access tokens, and DPoP proofs are logged.', + ); +}); diff --git a/e2e/dpop/compose.yml b/e2e/dpop/compose.yml new file mode 100644 index 0000000..e7ba48b --- /dev/null +++ b/e2e/dpop/compose.yml @@ -0,0 +1,69 @@ +name: fusionauth-dpop + +services: + react: + build: + context: ../.. + dockerfile: e2e/dpop/react/Dockerfile + args: + CLIENT_ID: ${REACT_CLIENT_ID:-replace-with-react-client-id} + labels: + dev.orbstack.http-port: '80' + healthcheck: + test: ['CMD', 'wget', '-q', '--spider', 'http://127.0.0.1/'] + interval: 5s + timeout: 2s + retries: 10 + + vue: + build: + context: ../.. + dockerfile: e2e/dpop/vue/Dockerfile + args: + CLIENT_ID: ${VUE_CLIENT_ID:-replace-with-vue-client-id} + labels: + dev.orbstack.http-port: '80' + healthcheck: + test: ['CMD', 'wget', '-q', '--spider', 'http://127.0.0.1/'] + interval: 5s + timeout: 2s + retries: 10 + + angular: + build: + context: ../.. + dockerfile: e2e/dpop/angular/Dockerfile + args: + CLIENT_ID: ${ANGULAR_CLIENT_ID:-replace-with-angular-client-id} + labels: + dev.orbstack.http-port: '80' + healthcheck: + test: ['CMD', 'wget', '-q', '--spider', 'http://127.0.0.1/'] + interval: 5s + timeout: 2s + retries: 10 + + api: + build: + context: ../.. + dockerfile: e2e/dpop/api/Dockerfile + environment: + API_EXTERNAL_ORIGIN: ${API_EXTERNAL_ORIGIN:-https://api.fusionauth-dpop.orb.local} + ANGULAR_CLIENT_ID: ${ANGULAR_CLIENT_ID:-replace-with-angular-client-id} + EXPECTED_ISSUER: ${EXPECTED_ISSUER:-https://example.com} + FUSIONAUTH_JWKS_URL: ${FUSIONAUTH_JWKS_URL:-http://host.orb.internal:9011/.well-known/jwks.json} + REACT_CLIENT_ID: ${REACT_CLIENT_ID:-replace-with-react-client-id} + VUE_CLIENT_ID: ${VUE_CLIENT_ID:-replace-with-vue-client-id} + labels: + dev.orbstack.http-port: '3000' + healthcheck: + test: + [ + 'CMD', + 'node', + '-e', + "fetch('http://127.0.0.1:3000/health').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))", + ] + interval: 5s + timeout: 2s + retries: 10 diff --git a/e2e/dpop/nginx.conf b/e2e/dpop/nginx.conf new file mode 100644 index 0000000..c56d2bf --- /dev/null +++ b/e2e/dpop/nginx.conf @@ -0,0 +1,10 @@ +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + + location / { + try_files $uri $uri/ /index.html; + } +} + diff --git a/e2e/dpop/react/Dockerfile b/e2e/dpop/react/Dockerfile new file mode 100644 index 0000000..d2a3b91 --- /dev/null +++ b/e2e/dpop/react/Dockerfile @@ -0,0 +1,25 @@ +FROM node:24.15.0-alpine AS sdk-build +WORKDIR /repo +ENV HUSKY=0 +COPY package.json yarn.lock tsconfig.json ./ +COPY packages ./packages +RUN corepack enable && corepack prepare yarn@1.22.22 --activate +RUN yarn install --frozen-lockfile --ignore-engines --non-interactive +RUN yarn build:sdk-react + +FROM node:24.15.0-alpine AS app-build +WORKDIR /app +ARG CLIENT_ID +ENV VITE_CLIENT_ID=$CLIENT_ID +RUN corepack enable && corepack prepare yarn@1.22.22 --activate +COPY e2e/dpop/react/package.json ./ +COPY --from=sdk-build /repo/packages/sdk-react/package.json ./vendor/react-sdk/package.json +COPY --from=sdk-build /repo/packages/sdk-react/dist ./vendor/react-sdk/dist +RUN yarn install --non-interactive +COPY e2e/dpop/react/index.html e2e/dpop/react/tsconfig.json e2e/dpop/react/vite.config.ts ./ +COPY e2e/dpop/react/src ./src +RUN yarn build + +FROM nginx:1.29-alpine +COPY e2e/dpop/nginx.conf /etc/nginx/conf.d/default.conf +COPY --from=app-build /app/dist /usr/share/nginx/html diff --git a/e2e/dpop/react/index.html b/e2e/dpop/react/index.html new file mode 100644 index 0000000..9e1c584 --- /dev/null +++ b/e2e/dpop/react/index.html @@ -0,0 +1,12 @@ + + + + + + React DPoP demo + + +
+ + + diff --git a/e2e/dpop/react/package.json b/e2e/dpop/react/package.json new file mode 100644 index 0000000..bda885a --- /dev/null +++ b/e2e/dpop/react/package.json @@ -0,0 +1,21 @@ +{ + "name": "dpop-react-demo", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "build": "tsc --noEmit && vite build" + }, + "dependencies": { + "@fusionauth/react-sdk": "file:vendor/react-sdk", + "react": "19.2.0", + "react-dom": "19.2.0" + }, + "devDependencies": { + "@types/react": "19.2.0", + "@types/react-dom": "19.2.0", + "@vitejs/plugin-react": "5.0.4", + "typescript": "5.9.3", + "vite": "7.1.7" + } +} diff --git a/e2e/dpop/react/src/App.tsx b/e2e/dpop/react/src/App.tsx new file mode 100644 index 0000000..ec7e5c2 --- /dev/null +++ b/e2e/dpop/react/src/App.tsx @@ -0,0 +1,34 @@ +import { useState } from 'react'; +import { useFusionAuth } from '@fusionauth/react-sdk'; + +const apiUrl = 'https://api.fusionauth-dpop.orb.local/resource'; + +export function App() { + const { dpopFetch, isLoggedIn, startLogin, startLogout } = useFusionAuth(); + const [result, setResult] = useState(''); + + async function callResource() { + try { + const response = await dpopFetch!(apiUrl); + const body = await response.text(); + setResult(response.ok ? body : `HTTP ${response.status}: ${body}`); + } catch (error) { + setResult(error instanceof Error ? error.message : 'Request failed'); + } + } + + return ( +
+

React DPoP demo

+ {isLoggedIn ? ( + <> + {' '} + + + ) : ( + + )} +
{result}
+
+ ); +} diff --git a/e2e/dpop/react/src/main.tsx b/e2e/dpop/react/src/main.tsx new file mode 100644 index 0000000..8812ae8 --- /dev/null +++ b/e2e/dpop/react/src/main.tsx @@ -0,0 +1,21 @@ +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; +import { FusionAuthProvider } from '@fusionauth/react-sdk'; +import { App } from './App'; + +const appUrl = 'https://react.fusionauth-dpop.orb.local'; + +createRoot(document.getElementById('root')!).render( + + + + + , +); diff --git a/e2e/dpop/react/tsconfig.json b/e2e/dpop/react/tsconfig.json new file mode 100644 index 0000000..6181286 --- /dev/null +++ b/e2e/dpop/react/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "jsx": "react-jsx", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "moduleResolution": "Bundler", + "noEmit": true, + "skipLibCheck": true, + "strict": true, + "target": "ES2022", + "types": ["vite/client"] + }, + "include": ["src"] +} diff --git a/e2e/dpop/react/vite.config.ts b/e2e/dpop/react/vite.config.ts new file mode 100644 index 0000000..fabde1a --- /dev/null +++ b/e2e/dpop/react/vite.config.ts @@ -0,0 +1,6 @@ +import react from '@vitejs/plugin-react'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + plugins: [react()], +}); diff --git a/e2e/dpop/vue/Dockerfile b/e2e/dpop/vue/Dockerfile new file mode 100644 index 0000000..36ac344 --- /dev/null +++ b/e2e/dpop/vue/Dockerfile @@ -0,0 +1,25 @@ +FROM node:24.15.0-alpine AS sdk-build +WORKDIR /repo +ENV HUSKY=0 +COPY package.json yarn.lock tsconfig.json ./ +COPY packages ./packages +RUN corepack enable && corepack prepare yarn@1.22.22 --activate +RUN yarn install --frozen-lockfile --ignore-engines --non-interactive +RUN yarn build:sdk-vue + +FROM node:24.15.0-alpine AS app-build +WORKDIR /app +ARG CLIENT_ID +ENV VITE_CLIENT_ID=$CLIENT_ID +RUN corepack enable && corepack prepare yarn@1.22.22 --activate +COPY e2e/dpop/vue/package.json ./ +COPY --from=sdk-build /repo/packages/sdk-vue/package.json ./vendor/vue-sdk/package.json +COPY --from=sdk-build /repo/packages/sdk-vue/dist ./vendor/vue-sdk/dist +RUN yarn install --non-interactive +COPY e2e/dpop/vue/index.html e2e/dpop/vue/tsconfig.json e2e/dpop/vue/vite.config.ts ./ +COPY e2e/dpop/vue/src ./src +RUN yarn build + +FROM nginx:1.29-alpine +COPY e2e/dpop/nginx.conf /etc/nginx/conf.d/default.conf +COPY --from=app-build /app/dist /usr/share/nginx/html diff --git a/e2e/dpop/vue/index.html b/e2e/dpop/vue/index.html new file mode 100644 index 0000000..a5b4286 --- /dev/null +++ b/e2e/dpop/vue/index.html @@ -0,0 +1,12 @@ + + + + + + Vue DPoP demo + + +
+ + + diff --git a/e2e/dpop/vue/package.json b/e2e/dpop/vue/package.json new file mode 100644 index 0000000..1f21bc1 --- /dev/null +++ b/e2e/dpop/vue/package.json @@ -0,0 +1,19 @@ +{ + "name": "dpop-vue-demo", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "build": "vue-tsc --noEmit && vite build" + }, + "dependencies": { + "@fusionauth/vue-sdk": "file:vendor/vue-sdk", + "vue": "3.5.22" + }, + "devDependencies": { + "@vitejs/plugin-vue": "6.0.1", + "typescript": "5.9.3", + "vite": "7.1.7", + "vue-tsc": "3.1.1" + } +} diff --git a/e2e/dpop/vue/src/App.vue b/e2e/dpop/vue/src/App.vue new file mode 100644 index 0000000..12732d2 --- /dev/null +++ b/e2e/dpop/vue/src/App.vue @@ -0,0 +1,30 @@ + + + diff --git a/e2e/dpop/vue/src/main.ts b/e2e/dpop/vue/src/main.ts new file mode 100644 index 0000000..5a9d322 --- /dev/null +++ b/e2e/dpop/vue/src/main.ts @@ -0,0 +1,16 @@ +import { createApp } from 'vue'; +import FusionAuthVuePlugin from '@fusionauth/vue-sdk'; +import App from './App.vue'; + +const appUrl = 'https://vue.fusionauth-dpop.orb.local'; + +createApp(App) + .use(FusionAuthVuePlugin, { + clientId: import.meta.env.VITE_CLIENT_ID, + dpopTokenStorage: 'localStorage', + postLogoutRedirectUri: appUrl, + redirectUri: appUrl, + serverUrl: 'https://local.fusionauth.io', + useDpop: true, + }) + .mount('#app'); diff --git a/e2e/dpop/vue/tsconfig.json b/e2e/dpop/vue/tsconfig.json new file mode 100644 index 0000000..f5ecf80 --- /dev/null +++ b/e2e/dpop/vue/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "moduleResolution": "Bundler", + "noEmit": true, + "skipLibCheck": true, + "strict": true, + "target": "ES2022", + "types": ["vite/client"] + }, + "include": ["src/**/*.ts", "src/**/*.vue"] +} diff --git a/e2e/dpop/vue/vite.config.ts b/e2e/dpop/vue/vite.config.ts new file mode 100644 index 0000000..7b6cf7e --- /dev/null +++ b/e2e/dpop/vue/vite.config.ts @@ -0,0 +1,6 @@ +import vue from '@vitejs/plugin-vue'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + plugins: [vue()], +}); diff --git a/packages/sdk-angular/docs/README.md b/packages/sdk-angular/docs/README.md index 179c520..f779f41 100644 --- a/packages/sdk-angular/docs/README.md +++ b/packages/sdk-angular/docs/README.md @@ -1,17 +1,250 @@ @fusionauth/angular-sdk / [Exports](modules.md) -# FusionauthAngularSdk +An SDK for using FusionAuth in Angular applications. -This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.2.0. +# Table of Contents -## Build +- [Overview](#overview) +- [Getting Started](#getting-started) +- [Quickstart](#quickstart) +- [Installation](#installation) +- [Usage](#usage) +- [FusionAuthService](#fusionauthservice) +- [Pre-built buttons](#pre-built-buttons) +- [State Parameter](#state-parameter) +- [SSR](#ssr) +- [DPoP Mode](#dpop-mode) +- [Known issues](#known-issues) +- [Documentation](#documentation) +- [Releases](#releases) -Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. + -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). +# Overview -## Further help + -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. +This SDK helps manage authentication state for your Angular app and provides functionality to login, register, and logout users. It also can be configured to automatically manage your refresh token. + +Your users will be sent to FusionAuth’s themeable hosted login pages and +then log in. After that, they are sent back to your Angular application. + +Once authentication succeeds, the following secure, HTTP-only cookies +will be set: + +- `app.at` - an OAuth [Access + Token](https://fusionauth.io/docs/v1/tech/oauth/tokens#access-token) + +- `app.rt` - a [Refresh + Token](https://fusionauth.io/docs/v1/tech/oauth/tokens#refresh-token) + used to obtain a new `app.at`. This cookie will only be set if + refresh tokens are enabled on your FusionAuth instance. + +The access token can be presented to APIs to authorize the request and +the refresh token can be used to get a new access token. + +There are 2 ways to interact with this SDK: + +1. By hosting your own server that performs the OAuth token exchange and meets the [server code requirements for FusionAuth Web SDKs](https://github.com/FusionAuth/fusionauth-javascript-sdk-express#server-code-requirements). +2. By using the server hosted on your FusionAuth instance, i.e., not writing your own server code. + +If you are hosting your own server, see [server code requirements](https://github.com/FusionAuth/fusionauth-javascript-sdk-express#server-code-requirements). + +You can use this library against any version of FusionAuth or any OIDC +compliant identity server. + +## Getting Started + +If you are new to Angular development, you may want to start with the Quickstart guide. If you are already familiar with Angular development, skip to the Installation section. + +### Quickstart + +See the [FusionAuth Angular Quickstart](https://fusionauth.io/docs/quickstarts/quickstart-javascript-angular-web) for a full tutorial on using FusionAuth and Angular. + +### Installation + +NPM: + +```bash +npm install @fusionauth/angular-sdk +``` + +Yarn: + +```bash +yarn add @fusionauth/angular-sdk +``` + +### Configuring FusionAuthModule + +```typescript +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppRoutingModule } from './app-routing.module'; +import { FusionAuthModule } from '@fusionauth/angular-sdk'; + +@NgModule({ + declarations: [], + imports: [ + FusionAuthModule.forRoot({ + clientId: '', // Your FusionAuth client ID + serverUrl: '', // The base URL of the server that performs the token exchange + redirectUri: '', // The URI that the user is directed to after the login/register/logout action + shouldAutoRefresh: true, // option to configure the SDK to automatically handle token refresh. Defaults to false if not specified here. + // useDpop: true, // Opt-in to DPoP mode. See "DPoP Mode" below. Defaults to false. + }), + ], + providers: [], + bootstrap: [], +}) +export class AppModule {} +``` + +## Usage + +### FusionAuthService + +The injectable `FusionAuthService` class provides observable properties to which components may subscribe. + +Note, you can also use the non-observable `getUserInfo` method if you wish to implement your observables. + +```typescript +class AppComponent implements OnInit, OnDestroy { + private fusionAuthService: FusionAuthService = inject(FusionAuthService); + + isLoggedIn: boolean = this.fusionAuthService.isLoggedIn(); + userInfo: UserInfo | null = null; + isGettingUserInfo: boolean = false; + subscription?: Subscription; + + ngOnInit(): void { + if (this.isLoggedIn) { + this.subscription = this.fusionAuthService + .getUserInfoObservable({ + onBegin: () => (this.isGettingUserInfo = true), + onDone: () => (this.isGettingUserInfo = false), + }) + .subscribe({ + next: userInfo => (this.userInfo = userInfo), + error: error => console.error(error), + }); + } + } + + ngOnDestroy(): void { + this.subscription?.unsubscribe(); + } +} +``` + +### Pre-built buttons + +There are three pre-styled buttons that are configured to perform +login/logout/registration. They can be placed anywhere in your app as +is. + +```typescript +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-login', + template: ``, + styleUrls: [], +}) +export class LoginComponent {} + +@Component({ + selector: 'app-logout', + template: ``, + styleUrls: [], +}) +export class LogoutComponent {} + +@Component({ + selector: 'app-register', + template: ``, + styleUrls: [], +}) +export class RegisterComponent {} +``` + +#### State parameter + +The `startLogin` and `startRegistration` functions both accept an optional string +parameter called `state`. The login and register components can also be passed the +state as an input. The state that is passed in to the function call will be echoed +back in the state query parameter of the callback uri specified in `redirectUri` on +the `FusionAuthConfig` used to initialize the `FusionAuthModule`. Though you may +pass any value you would like for the state parameter, it is often used to indicate +which page the user was on before redirecting to login or registration, so that the +user can be returned to that location after a successful authentication. + +#### SSR + +The SDK supports Angular applications using SSR. No additional configuration is needed. + +### DPoP Mode + +By default, the SDK calls a Hosted Backend that stores tokens in HttpOnly cookies (`useDpop: false`, the default). In DPoP mode, the SDK instead calls FusionAuth endpoints directly and binds tokens to a private key generated in the browser. Enable it by setting `useDpop: true` on `FusionAuthConfig`: + +```typescript +FusionAuthModule.forRoot({ + clientId: '', + serverUrl: '', + redirectUri: '', + useDpop: true, // Opt-in to DPoP mode. + dpopTokenStorage: 'localStorage', // 'localStorage' (default, persists across reloads) or 'memory'. +}), +``` + +When `useDpop: true`, `FusionAuthService` additionally exposes `dpopFetch()`, `generateProof()`, and `getAccessToken()`. These throw a descriptive error if called when `useDpop` is not enabled. + +```typescript +class AppComponent { + private fusionAuthService: FusionAuthService = inject(FusionAuthService); + + async callApi() { + // Recommended — handles attaching DPoP headers (and nonce retries) automatically. + const response = await this.fusionAuthService.dpopFetch( + 'https://api.example.com/data', + { method: 'GET' }, + ); + + // For axios or other HTTP libraries that can't use dpopFetch. + const accessToken = this.fusionAuthService.getAccessToken(); + const proof = await this.fusionAuthService.generateProof( + 'https://api.example.com/data', + 'GET', + accessToken ?? undefined, + ); + // axios.get('https://api.example.com/data', { + // headers: { Authorization: `DPoP ${accessToken}`, DPoP: proof } + // }); + } +} +``` + +### Known Issues + +None. + +## Documentation + +[Full library documentation](https://github.com/FusionAuth/fusionauth-javascript-sdk/tree/main/packages/sdk-angular/docs) + + + +Use backticks for code in this readme. This readme is included on the FusionAuth website, and backticks show the code in the best light there. + +## Releases + +To perform a release to NPM, create a release on GitHub. That will automatically publish a release to GitHub. diff --git a/packages/sdk-angular/docs/classes/FusionAuthAccountButtonComponent.md b/packages/sdk-angular/docs/classes/FusionAuthAccountButtonComponent.md index 476907d..23b908c 100644 --- a/packages/sdk-angular/docs/classes/FusionAuthAccountButtonComponent.md +++ b/packages/sdk-angular/docs/classes/FusionAuthAccountButtonComponent.md @@ -34,7 +34,7 @@ #### Defined in -[lib/components/fusionauth-account.button/fusion-auth-account-button.component.ts:10](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-account.button/fusion-auth-account-button.component.ts#L10) +[lib/components/fusionauth-account.button/fusion-auth-account-button.component.ts:11](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-account.button/fusion-auth-account-button.component.ts#L11) ## Properties @@ -44,7 +44,7 @@ #### Defined in -[lib/components/fusionauth-account.button/fusion-auth-account-button.component.ts:10](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-account.button/fusion-auth-account-button.component.ts#L10) +[lib/components/fusionauth-account.button/fusion-auth-account-button.component.ts:11](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-account.button/fusion-auth-account-button.component.ts#L11) ## Methods @@ -58,4 +58,4 @@ #### Defined in -[lib/components/fusionauth-account.button/fusion-auth-account-button.component.ts:12](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-account.button/fusion-auth-account-button.component.ts#L12) +[lib/components/fusionauth-account.button/fusion-auth-account-button.component.ts:13](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-account.button/fusion-auth-account-button.component.ts#L13) diff --git a/packages/sdk-angular/docs/classes/FusionAuthLoginButtonComponent.md b/packages/sdk-angular/docs/classes/FusionAuthLoginButtonComponent.md index 0722cf8..8c1ddd7 100644 --- a/packages/sdk-angular/docs/classes/FusionAuthLoginButtonComponent.md +++ b/packages/sdk-angular/docs/classes/FusionAuthLoginButtonComponent.md @@ -35,7 +35,7 @@ #### Defined in -[lib/components/fusionauth-login.button/fusion-auth-login-button.component.ts:12](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-login.button/fusion-auth-login-button.component.ts#L12) +[lib/components/fusionauth-login.button/fusion-auth-login-button.component.ts:13](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-login.button/fusion-auth-login-button.component.ts#L13) ## Properties @@ -45,7 +45,7 @@ #### Defined in -[lib/components/fusionauth-login.button/fusion-auth-login-button.component.ts:12](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-login.button/fusion-auth-login-button.component.ts#L12) +[lib/components/fusionauth-login.button/fusion-auth-login-button.component.ts:13](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-login.button/fusion-auth-login-button.component.ts#L13) --- @@ -55,7 +55,7 @@ #### Defined in -[lib/components/fusionauth-login.button/fusion-auth-login-button.component.ts:10](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-login.button/fusion-auth-login-button.component.ts#L10) +[lib/components/fusionauth-login.button/fusion-auth-login-button.component.ts:11](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-login.button/fusion-auth-login-button.component.ts#L11) ## Methods @@ -69,4 +69,4 @@ #### Defined in -[lib/components/fusionauth-login.button/fusion-auth-login-button.component.ts:14](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-login.button/fusion-auth-login-button.component.ts#L14) +[lib/components/fusionauth-login.button/fusion-auth-login-button.component.ts:15](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-login.button/fusion-auth-login-button.component.ts#L15) diff --git a/packages/sdk-angular/docs/classes/FusionAuthLogoutButtonComponent.md b/packages/sdk-angular/docs/classes/FusionAuthLogoutButtonComponent.md index fec4fe4..d5f9108 100644 --- a/packages/sdk-angular/docs/classes/FusionAuthLogoutButtonComponent.md +++ b/packages/sdk-angular/docs/classes/FusionAuthLogoutButtonComponent.md @@ -34,7 +34,7 @@ #### Defined in -[lib/components/fusionauth-logout.button/fusion-auth-logout-button.component.ts:10](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-logout.button/fusion-auth-logout-button.component.ts#L10) +[lib/components/fusionauth-logout.button/fusion-auth-logout-button.component.ts:14](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-logout.button/fusion-auth-logout-button.component.ts#L14) ## Properties @@ -44,7 +44,7 @@ #### Defined in -[lib/components/fusionauth-logout.button/fusion-auth-logout-button.component.ts:10](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-logout.button/fusion-auth-logout-button.component.ts#L10) +[lib/components/fusionauth-logout.button/fusion-auth-logout-button.component.ts:14](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-logout.button/fusion-auth-logout-button.component.ts#L14) ## Methods @@ -58,4 +58,4 @@ #### Defined in -[lib/components/fusionauth-logout.button/fusion-auth-logout-button.component.ts:12](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-logout.button/fusion-auth-logout-button.component.ts#L12) +[lib/components/fusionauth-logout.button/fusion-auth-logout-button.component.ts:16](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-logout.button/fusion-auth-logout-button.component.ts#L16) diff --git a/packages/sdk-angular/docs/classes/FusionAuthModule.md b/packages/sdk-angular/docs/classes/FusionAuthModule.md index 7465f17..93ecd29 100644 --- a/packages/sdk-angular/docs/classes/FusionAuthModule.md +++ b/packages/sdk-angular/docs/classes/FusionAuthModule.md @@ -40,4 +40,4 @@ #### Defined in -[lib/fusion-auth.module.ts:26](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.module.ts#L26) +[lib/fusion-auth.module.ts:26](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.module.ts#L26) diff --git a/packages/sdk-angular/docs/classes/FusionAuthRegisterButtonComponent.md b/packages/sdk-angular/docs/classes/FusionAuthRegisterButtonComponent.md index 8b75c77..157269c 100644 --- a/packages/sdk-angular/docs/classes/FusionAuthRegisterButtonComponent.md +++ b/packages/sdk-angular/docs/classes/FusionAuthRegisterButtonComponent.md @@ -35,7 +35,7 @@ #### Defined in -[lib/components/fusionauth-register.button/fusion-auth-register-button.component.ts:12](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-register.button/fusion-auth-register-button.component.ts#L12) +[lib/components/fusionauth-register.button/fusion-auth-register-button.component.ts:16](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-register.button/fusion-auth-register-button.component.ts#L16) ## Properties @@ -45,7 +45,7 @@ #### Defined in -[lib/components/fusionauth-register.button/fusion-auth-register-button.component.ts:12](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-register.button/fusion-auth-register-button.component.ts#L12) +[lib/components/fusionauth-register.button/fusion-auth-register-button.component.ts:16](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-register.button/fusion-auth-register-button.component.ts#L16) --- @@ -55,7 +55,7 @@ #### Defined in -[lib/components/fusionauth-register.button/fusion-auth-register-button.component.ts:10](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-register.button/fusion-auth-register-button.component.ts#L10) +[lib/components/fusionauth-register.button/fusion-auth-register-button.component.ts:14](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-register.button/fusion-auth-register-button.component.ts#L14) ## Methods @@ -69,4 +69,4 @@ #### Defined in -[lib/components/fusionauth-register.button/fusion-auth-register-button.component.ts:14](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-register.button/fusion-auth-register-button.component.ts#L14) +[lib/components/fusionauth-register.button/fusion-auth-register-button.component.ts:18](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/components/fusionauth-register.button/fusion-auth-register-button.component.ts#L18) diff --git a/packages/sdk-angular/docs/classes/FusionAuthService.md b/packages/sdk-angular/docs/classes/FusionAuthService.md index 3ca445c..c05c31c 100644 --- a/packages/sdk-angular/docs/classes/FusionAuthService.md +++ b/packages/sdk-angular/docs/classes/FusionAuthService.md @@ -21,10 +21,14 @@ Service class to use with FusionAuth backend endpoints. - [autoRefreshTimer](FusionAuthService.md#autorefreshtimer) - [core](FusionAuthService.md#core) - [isLoggedIn$](FusionAuthService.md#isloggedin$) -- [isLoggedInSubject](FusionAuthService.md#isloggedinsubject) +- [isLoggedInSignal](FusionAuthService.md#isloggedinsignal) +- [isLoggedInState](FusionAuthService.md#isloggedinstate) ### Methods +- [dpopFetch](FusionAuthService.md#dpopfetch) +- [generateProof](FusionAuthService.md#generateproof) +- [getAccessToken](FusionAuthService.md#getaccesstoken) - [getUserInfo](FusionAuthService.md#getuserinfo) - [getUserInfoObservable](FusionAuthService.md#getuserinfoobservable) - [initAutoRefresh](FusionAuthService.md#initautorefresh) @@ -60,7 +64,7 @@ Service class to use with FusionAuth backend endpoints. #### Defined in -[lib/fusion-auth.service.ts:21](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L21) +[lib/fusion-auth.service.ts:29](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L29) ## Properties @@ -70,7 +74,7 @@ Service class to use with FusionAuth backend endpoints. #### Defined in -[lib/fusion-auth.service.ts:18](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L18) +[lib/fusion-auth.service.ts:26](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L26) --- @@ -80,7 +84,7 @@ Service class to use with FusionAuth backend endpoints. #### Defined in -[lib/fusion-auth.service.ts:17](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L17) +[lib/fusion-auth.service.ts:25](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L25) --- @@ -92,20 +96,110 @@ An observable representing whether the user is logged in. #### Defined in -[lib/fusion-auth.service.ts:44](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L44) +[lib/fusion-auth.service.ts:58](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L58) --- -### isLoggedInSubject +### isLoggedInSignal -• `Private` **isLoggedInSubject**: `BehaviorSubject`\<`boolean`\> +• **isLoggedInSignal**: `Signal`\<`boolean`\> + +A Signal representing whether the user is logged in. + +#### Defined in + +[lib/fusion-auth.service.ts:63](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L63) + +--- + +### isLoggedInState + +• `Private` **isLoggedInState**: `WritableSignal`\<`boolean`\> #### Defined in -[lib/fusion-auth.service.ts:19](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L19) +[lib/fusion-auth.service.ts:27](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L27) ## Methods +### dpopFetch + +▸ **dpopFetch**(`input`, `init?`): `Promise`\<`Response`\> + +DPoP mode `fetch()` wrapper that automatically attaches DPoP proof +headers. + +#### Parameters + +| Name | Type | +| :------ | :--------------------- | +| `input` | `URL` \| `RequestInfo` | +| `init?` | `RequestInit` | + +#### Returns + +`Promise`\<`Response`\> + +**`Throws`** + +if called when `useDpop` is not enabled. + +#### Defined in + +[lib/fusion-auth.service.ts:163](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L163) + +--- + +### generateProof + +▸ **generateProof**(`htu`, `htm`, `accessToken?`, `nonce?`): `Promise`\<`string`\> + +Returns a signed DPoP proof JWT for use with axios or other +HTTP libraries that can't use [dpopFetch](FusionAuthService.md#dpopfetch). + +#### Parameters + +| Name | Type | +| :------------- | :------- | +| `htu` | `string` | +| `htm` | `string` | +| `accessToken?` | `string` | +| `nonce?` | `string` | + +#### Returns + +`Promise`\<`string`\> + +**`Throws`** + +if called when `useDpop` is not enabled. + +#### Defined in + +[lib/fusion-auth.service.ts:175](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L175) + +--- + +### getAccessToken + +▸ **getAccessToken**(): `null` \| `string` + +Returns the stored DPoP access token, or `null` if not logged in. + +#### Returns + +`null` \| `string` + +**`Throws`** + +if called when `useDpop` is not enabled. + +#### Defined in + +[lib/fusion-auth.service.ts:188](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L188) + +--- + ### getUserInfo ▸ **getUserInfo**\<`T`\>(): `Promise`\<`T`\> @@ -128,7 +222,7 @@ Fetches userInfo from the 'me' endpoint. #### Defined in -[lib/fusion-auth.service.ts:102](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L102) +[lib/fusion-auth.service.ts:123](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L123) --- @@ -152,7 +246,7 @@ Returns an observable request that fetches userInfo, and catches error. #### Defined in -[lib/fusion-auth.service.ts:74](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L74) +[lib/fusion-auth.service.ts:95](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L95) --- @@ -169,7 +263,7 @@ This is handled automatically if the SDK is configured with `shouldAutoRefresh`. #### Defined in -[lib/fusion-auth.service.ts:63](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L63) +[lib/fusion-auth.service.ts:84](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L84) --- @@ -185,7 +279,7 @@ A function that returns whether the user is logged in. This returned value is no #### Defined in -[lib/fusion-auth.service.ts:47](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L47) +[lib/fusion-auth.service.ts:66](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L66) --- @@ -201,7 +295,7 @@ Initiates logout flow. #### Defined in -[lib/fusion-auth.service.ts:125](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L125) +[lib/fusion-auth.service.ts:146](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L146) --- @@ -218,7 +312,7 @@ Self service account management is only available in FusionAuth paid plans. #### Defined in -[lib/fusion-auth.service.ts:133](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L133) +[lib/fusion-auth.service.ts:154](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L154) --- @@ -235,7 +329,7 @@ Automatic token refreshing can be enabled if the SDK is configured with `shouldA #### Defined in -[lib/fusion-auth.service.ts:55](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L55) +[lib/fusion-auth.service.ts:74](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L74) --- @@ -257,7 +351,7 @@ Initiates login flow. #### Defined in -[lib/fusion-auth.service.ts:110](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L110) +[lib/fusion-auth.service.ts:131](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L131) --- @@ -279,4 +373,4 @@ Initiates register flow. #### Defined in -[lib/fusion-auth.service.ts:118](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L118) +[lib/fusion-auth.service.ts:139](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts#L139) diff --git a/packages/sdk-angular/docs/interfaces/FusionAuthConfig.md b/packages/sdk-angular/docs/interfaces/FusionAuthConfig.md index 15f59eb..efeea70 100644 --- a/packages/sdk-angular/docs/interfaces/FusionAuthConfig.md +++ b/packages/sdk-angular/docs/interfaces/FusionAuthConfig.md @@ -10,10 +10,12 @@ Config for FusionAuth Angular SDK - [autoRefreshSecondsBeforeExpiry](FusionAuthConfig.md#autorefreshsecondsbeforeexpiry) - [clientId](FusionAuthConfig.md#clientid) +- [dpopTokenStorage](FusionAuthConfig.md#dpoptokenstorage) - [loginPath](FusionAuthConfig.md#loginpath) - [logoutPath](FusionAuthConfig.md#logoutpath) - [mePath](FusionAuthConfig.md#mepath) - [onAutoRefreshFailure](FusionAuthConfig.md#onautorefreshfailure) +- [onLoginFailure](FusionAuthConfig.md#onloginfailure) - [onRedirect](FusionAuthConfig.md#onredirect) - [postLogoutRedirectUri](FusionAuthConfig.md#postlogoutredirecturi) - [redirectUri](FusionAuthConfig.md#redirecturi) @@ -22,6 +24,7 @@ Config for FusionAuth Angular SDK - [serverUrl](FusionAuthConfig.md#serverurl) - [shouldAutoRefresh](FusionAuthConfig.md#shouldautorefresh) - [tokenRefreshPath](FusionAuthConfig.md#tokenrefreshpath) +- [useDpop](FusionAuthConfig.md#usedpop) ## Properties @@ -33,7 +36,7 @@ The number of seconds before the access token expiry when the auto refresh funct #### Defined in -[lib/types.ts:38](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L38) +[lib/types.ts:38](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L38) --- @@ -45,7 +48,20 @@ The client id of the application. #### Defined in -[lib/types.ts:13](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L13) +[lib/types.ts:13](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L13) + +--- + +### dpopTokenStorage + +• `Optional` **dpopTokenStorage**: `"localStorage"` \| `"memory"` + +Token storage location in DPoP mode. Only meaningful when `useDpop: true`. +Defaults to `'localStorage'`. + +#### Defined in + +[lib/types.ts:92](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L92) --- @@ -57,7 +73,7 @@ The path to the login endpoint. #### Defined in -[lib/types.ts:53](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L53) +[lib/types.ts:59](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L59) --- @@ -69,7 +85,7 @@ The path to the logout endpoint. #### Defined in -[lib/types.ts:63](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L63) +[lib/types.ts:69](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L69) --- @@ -81,7 +97,7 @@ The path to the me endpoint. #### Defined in -[lib/types.ts:73](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L73) +[lib/types.ts:79](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L79) --- @@ -107,7 +123,34 @@ Callback to be invoked if a request to refresh the access token fails during aut #### Defined in -[lib/types.ts:48](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L48) +[lib/types.ts:48](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L48) + +--- + +### onLoginFailure + +• `Optional` **onLoginFailure**: (`error`: `Error`) => `void` + +Callback invoked if a DPoP mode login/register/redirect exchange fails. +Only relevant when `useDpop: true`. + +#### Type declaration + +▸ (`error`): `void` + +##### Parameters + +| Name | Type | +| :------ | :------ | +| `error` | `Error` | + +##### Returns + +`void` + +#### Defined in + +[lib/types.ts:54](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L54) --- @@ -133,7 +176,7 @@ Callback function to be invoked with the `state` value upon redirect from login #### Defined in -[lib/types.ts:43](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L43) +[lib/types.ts:43](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L43) --- @@ -145,7 +188,7 @@ The redirect URI for post-logout. Defaults the provided `redirectUri`. #### Defined in -[lib/types.ts:23](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L23) +[lib/types.ts:23](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L23) --- @@ -157,7 +200,7 @@ The redirect URI of the application. #### Defined in -[lib/types.ts:18](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L18) +[lib/types.ts:18](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L18) --- @@ -169,7 +212,7 @@ The path to the register endpoint. #### Defined in -[lib/types.ts:58](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L58) +[lib/types.ts:64](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L64) --- @@ -181,7 +224,7 @@ The OAuth2 scope parameter passed to the `/oauth2/authorize` endpoint. If not sp #### Defined in -[lib/types.ts:28](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L28) +[lib/types.ts:28](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L28) --- @@ -193,7 +236,7 @@ The URL of the server that performs the token exchange. #### Defined in -[lib/types.ts:8](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L8) +[lib/types.ts:8](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L8) --- @@ -205,7 +248,7 @@ Enables automatic token refreshing. Defaults to false. #### Defined in -[lib/types.ts:33](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L33) +[lib/types.ts:33](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L33) --- @@ -217,4 +260,18 @@ The path to the token refresh endpoint. #### Defined in -[lib/types.ts:68](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L68) +[lib/types.ts:74](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L74) + +--- + +### useDpop + +• `Optional` **useDpop**: `boolean` + +Opt-in to DPoP mode. When `true`, the SDK calls FusionAuth endpoints +directly and stores tokens in JavaScript-accessible storage instead of +relying on the Hosted Backend's HttpOnly cookies. Defaults to `false`. + +#### Defined in + +[lib/types.ts:86](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L86) diff --git a/packages/sdk-angular/docs/interfaces/UserInfo.md b/packages/sdk-angular/docs/interfaces/UserInfo.md index 3eaac8f..5459d54 100644 --- a/packages/sdk-angular/docs/interfaces/UserInfo.md +++ b/packages/sdk-angular/docs/interfaces/UserInfo.md @@ -9,14 +9,14 @@ - [applicationId](UserInfo.md#applicationid) - [birthdate](UserInfo.md#birthdate) - [email](UserInfo.md#email) -- [email_verified](UserInfo.md#email_verified) -- [family_name](UserInfo.md#family_name) -- [given_name](UserInfo.md#given_name) -- [middle_name](UserInfo.md#middle_name) +- [email\_verified](UserInfo.md#email_verified) +- [family\_name](UserInfo.md#family_name) +- [given\_name](UserInfo.md#given_name) +- [middle\_name](UserInfo.md#middle_name) - [name](UserInfo.md#name) -- [phone_number](UserInfo.md#phone_number) +- [phone\_number](UserInfo.md#phone_number) - [picture](UserInfo.md#picture) -- [preferred_username](UserInfo.md#preferred_username) +- [preferred\_username](UserInfo.md#preferred_username) - [roles](UserInfo.md#roles) - [sid](UserInfo.md#sid) - [sub](UserInfo.md#sub) @@ -30,7 +30,7 @@ #### Defined in -[lib/types.ts:77](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L77) +[lib/types.ts:96](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L96) --- @@ -40,7 +40,7 @@ #### Defined in -[lib/types.ts:78](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L78) +[lib/types.ts:97](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L97) --- @@ -50,47 +50,47 @@ #### Defined in -[lib/types.ts:79](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L79) +[lib/types.ts:98](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L98) --- -### email_verified +### email\_verified -• `Optional` **email_verified**: `boolean` +• `Optional` **email\_verified**: `boolean` #### Defined in -[lib/types.ts:80](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L80) +[lib/types.ts:99](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L99) --- -### family_name +### family\_name -• `Optional` **family_name**: `string` +• `Optional` **family\_name**: `string` #### Defined in -[lib/types.ts:81](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L81) +[lib/types.ts:100](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L100) --- -### given_name +### given\_name -• `Optional` **given_name**: `string` +• `Optional` **given\_name**: `string` #### Defined in -[lib/types.ts:82](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L82) +[lib/types.ts:101](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L101) --- -### middle_name +### middle\_name -• `Optional` **middle_name**: `string` +• `Optional` **middle\_name**: `string` #### Defined in -[lib/types.ts:83](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L83) +[lib/types.ts:102](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L102) --- @@ -100,17 +100,17 @@ #### Defined in -[lib/types.ts:84](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L84) +[lib/types.ts:103](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L103) --- -### phone_number +### phone\_number -• `Optional` **phone_number**: `string` +• `Optional` **phone\_number**: `string` #### Defined in -[lib/types.ts:85](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L85) +[lib/types.ts:104](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L104) --- @@ -120,17 +120,17 @@ #### Defined in -[lib/types.ts:86](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L86) +[lib/types.ts:105](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L105) --- -### preferred_username +### preferred\_username -• `Optional` **preferred_username**: `string` +• `Optional` **preferred\_username**: `string` #### Defined in -[lib/types.ts:87](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L87) +[lib/types.ts:106](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L106) --- @@ -140,7 +140,7 @@ #### Defined in -[lib/types.ts:88](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L88) +[lib/types.ts:107](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L107) --- @@ -150,7 +150,7 @@ #### Defined in -[lib/types.ts:89](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L89) +[lib/types.ts:108](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L108) --- @@ -160,7 +160,7 @@ #### Defined in -[lib/types.ts:90](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L90) +[lib/types.ts:109](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L109) --- @@ -170,4 +170,4 @@ #### Defined in -[lib/types.ts:91](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/80c01c9ccb450a2187bc0d2cc65fa8c9c38cfabe/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L91) +[lib/types.ts:110](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts#L110) diff --git a/packages/sdk-angular/package.json b/packages/sdk-angular/package.json index 2224ee8..b3ebbbe 100644 --- a/packages/sdk-angular/package.json +++ b/packages/sdk-angular/package.json @@ -7,7 +7,7 @@ "build": "yarn get-sdk-core && ng build && cp README.md dist/fusionauth-angular-sdk/README.md", "test": "yarn get-sdk-core && ng test --watch=false", "test:watch": "yarn get-sdk-core && ng test", - "docs": "typedoc --plugin typedoc-plugin-markdown" + "docs": "typedoc --plugin typedoc-plugin-markdown --tsconfig tsconfig.doc.json" }, "private": false, "dependencies": { diff --git a/packages/sdk-angular/projects/fusionauth-angular-sdk/README.md b/packages/sdk-angular/projects/fusionauth-angular-sdk/README.md deleted file mode 100644 index e7cd5a3..0000000 --- a/packages/sdk-angular/projects/fusionauth-angular-sdk/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# FusionauthAngularSdk - -This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.2.0. - -## Build - -Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. - -## Running unit tests - -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). - -## Further help - -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. \ No newline at end of file diff --git a/packages/sdk-angular/tsconfig.doc.json b/packages/sdk-angular/tsconfig.doc.json new file mode 100644 index 0000000..b36e096 --- /dev/null +++ b/packages/sdk-angular/tsconfig.doc.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "ignoreDeprecations": "5.0" + }, + "exclude": ["**/*.spec.ts"], + "typedocOptions": { + "plugin": ["typedoc-plugin-markdown"], + "entryPoints": ["projects/fusionauth-angular-sdk/src/public-api.ts"], + "out": "docs" + } +} diff --git a/packages/sdk-angular/tsconfig.json b/packages/sdk-angular/tsconfig.json index 6887e8e..87d5a16 100644 --- a/packages/sdk-angular/tsconfig.json +++ b/packages/sdk-angular/tsconfig.json @@ -27,7 +27,7 @@ "composite": false, "allowImportingTsExtensions": false, "noEmit": false, - "types": ["jasmine"] + "types": ["node"] }, "include": ["./**/*.ts"], "angularCompilerOptions": { @@ -35,10 +35,5 @@ "strictInjectionParameters": true, "strictInputAccessModifiers": true, "strictTemplates": true - }, - "typedocOptions": { - "plugin": ["typedoc-plugin-markdown"], - "entryPoints": ["projects/fusionauth-angular-sdk/src/public-api.ts"], - "out": "docs" } } diff --git a/packages/sdk-react/docs/README.md b/packages/sdk-react/docs/README.md index 0d68dd0..97bd5f2 100644 --- a/packages/sdk-react/docs/README.md +++ b/packages/sdk-react/docs/README.md @@ -11,10 +11,11 @@ An SDK for using FusionAuth in React applications. - [Configuration](#configuration) - [Configuration with NextJS](#configuration-with-nextjs) - [Usage](#usage) - - [useFusionAuth](#usefusionauth) - - [State Parameter](#state-parameter) - - [Protecting content](#protecting-content) - - [UI Components](#ui-components) + - [useFusionAuth](#usefusionauth) + - [State Parameter](#state-parameter) + - [Protecting content](#protecting-content) + - [UI Components](#ui-components) + - [DPoP Mode](#dpop-mode) - [Known issues](#known-issues) - [Documentation](#documentation) - [Formatting](#formatting) @@ -41,18 +42,19 @@ then log in. After that, they are sent back to your React application. Once authentication succeeds, the following secure, HTTP-only cookies will be set: -- `app.at` - an OAuth [Access - Token](https://fusionauth.io/docs/v1/tech/oauth/tokens#access-token) +- `app.at` - an OAuth [Access + Token](https://fusionauth.io/docs/v1/tech/oauth/tokens#access-token) -- `app.rt` - a [Refresh - Token](https://fusionauth.io/docs/v1/tech/oauth/tokens#refresh-token) - used to obtain a new `app.at`. This cookie will only be set if - refresh tokens are enabled on your FusionAuth instance. +- `app.rt` - a [Refresh + Token](https://fusionauth.io/docs/v1/tech/oauth/tokens#refresh-token) + used to obtain a new `app.at`. This cookie will only be set if + refresh tokens are enabled on your FusionAuth instance. The access token can be presented to APIs to authorize the request and the refresh token can be used to get a new access token. There are 2 ways to interact with this SDK: + 1. By hosting your own server that performs the OAuth token exchange and meets the [server code requirements for FusionAuth Web SDKs](https://github.com/FusionAuth/fusionauth-javascript-sdk-express#server-code-requirements). 2. By using the server hosted on your FusionAuth instance, i.e., not writing your own server code. @@ -98,6 +100,7 @@ const config: FusionAuthProviderConfig = { shouldAutoFetchUserInfo: true, // Automatically fetch userInfo when logged in. Defaults to false. shouldAutoRefresh: true, // Enables automatic token refresh. Defaults to false. onRedirect: (state?: string) => { }, // Optional callback invoked upon redirect back from login or register. + // useDpop: true, // Opt-in to DPoP mode. See "DPoP Mode" below. Defaults to false. }; ReactDOM.createRoot(document.getElementById("my-app")).render( @@ -112,7 +115,7 @@ ReactDOM.createRoot(document.getElementById("my-app")).render( To configure the SDK with Next, install [`next-client-cookies`](https://github.com/moshest/next-client-cookies?tab=readme-ov-file#install) and pass `useCookies` into the config object as `nextCookieAdapter`. ```jsx -'use client' +'use client'; import { useCookies } from 'next-client-cookies'; @@ -144,11 +147,11 @@ function MyComponent() { isFetchingUserInfo, startLogin, startRegister, - userInfo - } = useFusionAuth() + userInfo, + } = useFusionAuth(); if (isFetchingUserInfo) { - return

Loading...

+ return

Loading...

; } if (!isLoggedIn) { @@ -162,7 +165,7 @@ function MyComponent() { } if (userInfo?.given_name) { - return

Welcome {userInfo.given_name}!

+ return

Welcome {userInfo.given_name}!

; } } ``` @@ -186,9 +189,10 @@ const UserNameDisplay = () => { return ( <> -

User: {userInfo.given_name}

// Only displays if user is authenticated +

User: {userInfo.given_name}

// Only displays if user is + authenticated
- +

Please log in to view this page

@@ -198,7 +202,8 @@ const UserNameDisplay = () => { const AdminPanel = () => ( - // Only displays if user is authenticated and has 'admin' role + // Only displays if user is authenticated and + has 'admin' role ); ``` @@ -211,7 +216,7 @@ This SDK offers 3 pre-built UI components. import { FusionAuthLoginButton, FusionAuthLogoutButton, - FusionAuthRegisterButton + FusionAuthRegisterButton, } from '@fusionauth/react-sdk'; export const LoginPage = () => ( @@ -230,6 +235,42 @@ export const AccountPage = () => ( ); ``` +### DPoP Mode + +By default, the SDK calls a Hosted Backend that stores tokens in HttpOnly cookies (`useDpop: false`, the default). In DPoP mode, the SDK instead calls FusionAuth endpoints directly and binds tokens to a private key generated in the browser, per [RFC 9449](https://datatracker.ietf.org/doc/html/rfc9449). Enable it by setting `useDpop: true` on `FusionAuthProviderConfig`: + +```jsx +const config: FusionAuthProviderConfig = { + clientId: "", + redirectUri: "", + serverUrl: "", + useDpop: true, // Opt-in to DPoP mode. + dpopTokenStorage: 'localStorage', // 'localStorage' (default, persists across reloads) or 'memory'. +}; +``` + +When `useDpop: true`, `useFusionAuth()` additionally returns `dpopFetch`, `generateProof`, and `getAccessToken`. These are `undefined` when `useDpop` is `false` or not set. + +```jsx +const { dpopFetch, generateProof, getAccessToken } = useFusionAuth(); + +// Recommended — handles attaching DPoP headers (and nonce retries) automatically. +const response = await dpopFetch('https://api.example.com/data', { + method: 'GET', +}); + +// Advanced — for axios or other HTTP libraries that can't use dpopFetch. +const accessToken = getAccessToken(); +const proof = await generateProof( + 'https://api.example.com/data', + 'GET', + accessToken, +); +// axios.get('https://api.example.com/data', { +// headers: { Authorization: `DPoP ${accessToken}`, DPoP: proof } +// }); +``` + ### Known Issues None. @@ -248,8 +289,8 @@ end::forDocSite[] There are several linting packages run when you push to a branch. One is `prettier`. If this fails, you can fix the files from the command line: -* npm run install -* npm run prettier -- -w /path/to/file +- npm run install +- npm run prettier -- -w /path/to/file Doing this will overwrite your file, but fix prettier's objections. diff --git a/packages/sdk-react/docs/interfaces/providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md b/packages/sdk-react/docs/interfaces/providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md index 9cbbf2e..8ef1c89 100644 --- a/packages/sdk-react/docs/interfaces/providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md +++ b/packages/sdk-react/docs/interfaces/providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md @@ -14,11 +14,13 @@ Config for FusionAuthProvider - [authParams](providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md#authparams) - [autoRefreshSecondsBeforeExpiry](providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md#autorefreshsecondsbeforeexpiry) - [clientId](providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md#clientid) +- [dpopTokenStorage](providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md#dpoptokenstorage) - [loginPath](providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md#loginpath) - [logoutPath](providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md#logoutpath) - [mePath](providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md#mepath) - [nextCookieAdapter](providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md#nextcookieadapter) - [onAutoRefreshFailure](providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md#onautorefreshfailure) +- [onLoginFailure](providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md#onloginfailure) - [onRedirect](providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md#onredirect) - [postLogoutRedirectUri](providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md#postlogoutredirecturi) - [redirectUri](providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md#redirecturi) @@ -28,6 +30,7 @@ Config for FusionAuthProvider - [shouldAutoFetchUserInfo](providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md#shouldautofetchuserinfo) - [shouldAutoRefresh](providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md#shouldautorefresh) - [tokenRefreshPath](providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md#tokenrefreshpath) +- [useDpop](providers_FusionAuthProviderConfig.FusionAuthProviderConfig.md#usedpop) ## Properties @@ -40,7 +43,7 @@ Only set this if you are hosting server that uses a custom name for the 'app.at_ #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:98](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L98) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:104](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L104) --- @@ -52,7 +55,7 @@ Additional params passed to loginPath typically `/app/login/`, which redirects t #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:30](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L30) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:30](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L30) --- @@ -64,7 +67,7 @@ The number of seconds before the access token expiry when the auto refresh funct #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:50](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L50) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:50](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L50) --- @@ -76,7 +79,20 @@ The client id of the application. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:15](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L15) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:15](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L15) + +--- + +### dpopTokenStorage + +• `Optional` **dpopTokenStorage**: `"localStorage"` \| `"memory"` + +Token storage location in DPoP mode. Only meaningful when `useDpop: true`. +Defaults to `'localStorage'`. + +#### Defined in + +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:117](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L117) --- @@ -88,7 +104,7 @@ The path to the login endpoint. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:65](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L65) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:71](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L71) --- @@ -100,7 +116,7 @@ The path to the logout endpoint. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:75](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L75) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:81](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L81) --- @@ -112,7 +128,7 @@ The path to the me endpoint. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:92](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L92) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:98](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L98) --- @@ -134,7 +150,7 @@ See docs for [configuration with nextjs](https://github.com/FusionAuth/fusionaut #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:87](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L87) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:93](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L93) --- @@ -160,7 +176,34 @@ Callback to be invoked if a request to refresh the access token fails during aut #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:60](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L60) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:60](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L60) + +--- + +### onLoginFailure + +• `Optional` **onLoginFailure**: (`error`: `Error`) => `void` + +Callback invoked if a DPoP mode login/register/redirect exchange fails. +Only relevant when `useDpop: true`. + +#### Type declaration + +▸ (`error`): `void` + +##### Parameters + +| Name | Type | +| :------ | :------ | +| `error` | `Error` | + +##### Returns + +`void` + +#### Defined in + +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:66](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L66) --- @@ -186,7 +229,7 @@ Callback function to be invoked with the `state` value upon redirect from login #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:55](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L55) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:55](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L55) --- @@ -198,7 +241,7 @@ The redirect URI for post-logout. Defaults the provided `redirectUri`. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:35](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L35) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:35](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L35) --- @@ -210,7 +253,7 @@ The redirect URI of the application. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:20](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L20) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:20](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L20) --- @@ -222,7 +265,7 @@ The path to the register endpoint. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:70](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L70) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:76](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L76) --- @@ -234,7 +277,7 @@ The OAuth2 scope parameter passed to the `/oauth2/authorize` endpoint. If not sp #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:25](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L25) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:25](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L25) --- @@ -246,7 +289,7 @@ The URL of the server that performs the token exchange. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:10](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L10) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:10](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L10) --- @@ -258,7 +301,7 @@ Enables the SDK to automatically handle fetching user info when logged in. Defau #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:45](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L45) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:45](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L45) --- @@ -270,7 +313,7 @@ Enables automatic token refreshing. Defaults to false. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:40](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L40) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:40](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L40) --- @@ -282,4 +325,18 @@ The path to the token refresh endpoint. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:80](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L80) +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:86](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L86) + +--- + +### useDpop + +• `Optional` **useDpop**: `boolean` + +Opt-in to DPoP mode. When `true`, the SDK calls FusionAuth endpoints +directly and stores tokens in JavaScript-accessible storage instead of +relying on the Hosted Backend's HttpOnly cookies. Defaults to `false`. + +#### Defined in + +[packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts:111](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts#L111) diff --git a/packages/sdk-react/docs/interfaces/providers_FusionAuthProviderContext.FusionAuthProviderContext.md b/packages/sdk-react/docs/interfaces/providers_FusionAuthProviderContext.FusionAuthProviderContext.md index 8ed7bb9..39f9149 100644 --- a/packages/sdk-react/docs/interfaces/providers_FusionAuthProviderContext.FusionAuthProviderContext.md +++ b/packages/sdk-react/docs/interfaces/providers_FusionAuthProviderContext.FusionAuthProviderContext.md @@ -16,8 +16,11 @@ The context provided by FusionAuth React SDK ### Properties +- [dpopFetch](providers_FusionAuthProviderContext.FusionAuthProviderContext.md#dpopfetch) - [error](providers_FusionAuthProviderContext.FusionAuthProviderContext.md#error) - [fetchUserInfo](providers_FusionAuthProviderContext.FusionAuthProviderContext.md#fetchuserinfo) +- [generateProof](providers_FusionAuthProviderContext.FusionAuthProviderContext.md#generateproof) +- [getAccessToken](providers_FusionAuthProviderContext.FusionAuthProviderContext.md#getaccesstoken) - [initAutoRefresh](providers_FusionAuthProviderContext.FusionAuthProviderContext.md#initautorefresh) - [isFetchingUserInfo](providers_FusionAuthProviderContext.FusionAuthProviderContext.md#isfetchinguserinfo) - [isLoggedIn](providers_FusionAuthProviderContext.FusionAuthProviderContext.md#isloggedin) @@ -30,6 +33,34 @@ The context provided by FusionAuth React SDK ## Properties +### dpopFetch + +• `Optional` **dpopFetch**: (`input`: `RequestInfo` \| `URL`, `init?`: `RequestInit`) => `Promise`\<`Response`\> + +Fetch wrapper that automatically attaches DPoP proof headers. +Present only when `useDpop: true`. + +#### Type declaration + +▸ (`input`, `init?`): `Promise`\<`Response`\> + +##### Parameters + +| Name | Type | +| :------ | :--------------------- | +| `input` | `RequestInfo` \| `URL` | +| `init?` | `RequestInit` | + +##### Returns + +`Promise`\<`Response`\> + +#### Defined in + +[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:70](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L70) + +--- + ### error • **error**: `null` \| `Error` @@ -38,7 +69,7 @@ Error occurred while fetching userInfo. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:29](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L29) +[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:29](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L29) --- @@ -59,7 +90,59 @@ This is handled automatically if the SDK is configured with `shouldAutoFetchUser #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:19](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L19) +[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:19](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L19) + +--- + +### generateProof + +• `Optional` **generateProof**: (`htu`: `string`, `htm`: `string`, `accessToken?`: `string`, `nonce?`: `string`) => `Promise`\<`string`\> + +Returns a signed DPoP proof JWT for use with axios or other +HTTP libraries. Present only when `useDpop: true`. + +#### Type declaration + +▸ (`htu`, `htm`, `accessToken?`, `nonce?`): `Promise`\<`string`\> + +##### Parameters + +| Name | Type | +| :------------- | :------- | +| `htu` | `string` | +| `htm` | `string` | +| `accessToken?` | `string` | +| `nonce?` | `string` | + +##### Returns + +`Promise`\<`string`\> + +#### Defined in + +[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:79](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L79) + +--- + +### getAccessToken + +• `Optional` **getAccessToken**: () => `null` \| `string` + +Returns the stored DPoP access token, or `null` if not logged in. +Throws a descriptive error when `useDpop: false`. +Present only when `useDpop: true`. + +#### Type declaration + +▸ (): `null` \| `string` + +##### Returns + +`null` \| `string` + +#### Defined in + +[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:91](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L91) --- @@ -80,7 +163,7 @@ This is handled automatically if the SDK is configured with `shouldAutoRefresh`. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:64](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L64) +[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:64](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L64) --- @@ -92,7 +175,7 @@ Indicates that the fetchUserInfo call is unresolved. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:24](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L24) +[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:24](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L24) --- @@ -104,7 +187,7 @@ Whether the user is logged in. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:8](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L8) +[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:8](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L8) --- @@ -125,7 +208,7 @@ Self service account management is only available in FusionAuth paid plans. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:52](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L52) +[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:52](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L52) --- @@ -146,7 +229,7 @@ This is handled automatically if the SDK is configured with `shouldAutoRefresh`. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:58](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L58) +[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:58](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L58) --- @@ -172,7 +255,7 @@ Initiates login flow. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:35](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L35) +[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:35](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L35) --- @@ -192,7 +275,7 @@ Initiates logout flow. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:46](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L46) +[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:46](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L46) --- @@ -218,7 +301,7 @@ Initiates register flow. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:41](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L41) +[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:41](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L41) --- @@ -230,4 +313,4 @@ Data fetched from the configured 'me' endpoint. #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:13](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L13) +[packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts:13](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts#L13) diff --git a/packages/sdk-react/docs/modules/providers_FusionAuthProvider.md b/packages/sdk-react/docs/modules/providers_FusionAuthProvider.md index f84520b..d3249e9 100644 --- a/packages/sdk-react/docs/modules/providers_FusionAuthProvider.md +++ b/packages/sdk-react/docs/modules/providers_FusionAuthProvider.md @@ -33,7 +33,7 @@ #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProvider.tsx:21](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProvider.tsx#L21) +[packages/sdk-react/src/components/providers/FusionAuthProvider.tsx:23](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProvider.tsx#L23) --- @@ -55,4 +55,4 @@ A hook that returns `FusionAuthProviderContext` #### Defined in -[packages/sdk-react/src/components/providers/FusionAuthProvider.tsx:122](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/providers/FusionAuthProvider.tsx#L122) +[packages/sdk-react/src/components/providers/FusionAuthProvider.tsx:158](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/providers/FusionAuthProvider.tsx#L158) diff --git a/packages/sdk-react/docs/modules/ui_FusionAuthLoginButton.md b/packages/sdk-react/docs/modules/ui_FusionAuthLoginButton.md index 4ba81bf..c1164d6 100644 --- a/packages/sdk-react/docs/modules/ui_FusionAuthLoginButton.md +++ b/packages/sdk-react/docs/modules/ui_FusionAuthLoginButton.md @@ -28,4 +28,4 @@ Calls the `startLogin` method from `FusionAuthProviderContext`. #### Defined in -[packages/sdk-react/src/components/ui/FusionAuthLoginButton/index.tsx:16](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/ui/FusionAuthLoginButton/index.tsx#L16) +[packages/sdk-react/src/components/ui/FusionAuthLoginButton/index.tsx:16](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/ui/FusionAuthLoginButton/index.tsx#L16) diff --git a/packages/sdk-react/docs/modules/ui_FusionAuthLogoutButton.md b/packages/sdk-react/docs/modules/ui_FusionAuthLogoutButton.md index 67e103c..aeebe81 100644 --- a/packages/sdk-react/docs/modules/ui_FusionAuthLogoutButton.md +++ b/packages/sdk-react/docs/modules/ui_FusionAuthLogoutButton.md @@ -28,4 +28,4 @@ Calls the `startLogout` method from `FusionAuthProviderContext`. #### Defined in -[packages/sdk-react/src/components/ui/FusionAuthLogoutButton/index.tsx:13](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/ui/FusionAuthLogoutButton/index.tsx#L13) +[packages/sdk-react/src/components/ui/FusionAuthLogoutButton/index.tsx:13](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/ui/FusionAuthLogoutButton/index.tsx#L13) diff --git a/packages/sdk-react/docs/modules/ui_FusionAuthRegisterButton.md b/packages/sdk-react/docs/modules/ui_FusionAuthRegisterButton.md index 30a2074..d1a7724 100644 --- a/packages/sdk-react/docs/modules/ui_FusionAuthRegisterButton.md +++ b/packages/sdk-react/docs/modules/ui_FusionAuthRegisterButton.md @@ -28,4 +28,4 @@ Calls the `startRegister` method from `FusionAuthProviderContext`. #### Defined in -[packages/sdk-react/src/components/ui/FusionAuthRegisterButton/index.tsx:15](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/ui/FusionAuthRegisterButton/index.tsx#L15) +[packages/sdk-react/src/components/ui/FusionAuthRegisterButton/index.tsx:15](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/ui/FusionAuthRegisterButton/index.tsx#L15) diff --git a/packages/sdk-react/docs/modules/ui_RequireAuth.md b/packages/sdk-react/docs/modules/ui_RequireAuth.md index 50286a5..e61b8b9 100644 --- a/packages/sdk-react/docs/modules/ui_RequireAuth.md +++ b/packages/sdk-react/docs/modules/ui_RequireAuth.md @@ -28,4 +28,4 @@ Only renders children when user is authenticated. #### Defined in -[packages/sdk-react/src/components/ui/RequireAuth/index.tsx:10](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/ui/RequireAuth/index.tsx#L10) +[packages/sdk-react/src/components/ui/RequireAuth/index.tsx:10](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/ui/RequireAuth/index.tsx#L10) diff --git a/packages/sdk-react/docs/modules/ui_Unauthenticated.md b/packages/sdk-react/docs/modules/ui_Unauthenticated.md index 577dbf5..b201384 100644 --- a/packages/sdk-react/docs/modules/ui_Unauthenticated.md +++ b/packages/sdk-react/docs/modules/ui_Unauthenticated.md @@ -29,4 +29,4 @@ Only renders children when user is unauthenticated. #### Defined in -[packages/sdk-react/src/components/ui/Unauthenticated/index.tsx:5](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/63efa2d5360c2b7e1392ffa730dac8f5a0bc8e19/packages/sdk-react/src/components/ui/Unauthenticated/index.tsx#L5) +[packages/sdk-react/src/components/ui/Unauthenticated/index.tsx:5](https://github.com/FusionAuth/fusionauth-javascript-sdk/blob/97b137f4922b7072a3d647cca72fc0a02412325b/packages/sdk-react/src/components/ui/Unauthenticated/index.tsx#L5) diff --git a/packages/sdk-vue/docs/README.md b/packages/sdk-vue/docs/README.md index b9f215c..7caf6b0 100644 --- a/packages/sdk-vue/docs/README.md +++ b/packages/sdk-vue/docs/README.md @@ -6,16 +6,17 @@ An SDK for using FusionAuth in Vue applications. - [Overview](#overview) - [Getting Started](#getting-started) -- [Installation](#installation) + - [Quickstart](#quickstart) + - [Installation](#installation) - [Usage](#usage) - [Configuring the SDK](#configuring-the-sdk) - [Configuring with Nuxt](#configuring-with-nuxt) - [useFusionAuth Composable](#usefusionauth-composable) - [State parameter](#state-parameter) + - [DPoP Mode](#dpop-mode) - [UI Components](#ui-components) - [Protecting Content](#protecting-content) - [Pre-built buttons](#pre-built-buttons) -- [Quickstart](#quickstart) - [Documentation](#documentation) - [Known Issues](#known-issues) - [Releases](#releases) @@ -41,18 +42,19 @@ then log in. After that, they are sent back to your Vue application. Once authentication succeeds, the following secure, HTTP-only cookies will be set: -- `app.at` - an OAuth [Access - Token](https://fusionauth.io/docs/v1/tech/oauth/tokens#access-token) +- `app.at` - an OAuth [Access + Token](https://fusionauth.io/docs/v1/tech/oauth/tokens#access-token) -- `app.rt` - a [Refresh - Token](https://fusionauth.io/docs/v1/tech/oauth/tokens#refresh-token) - used to obtain a new `app.at`. This cookie will only be set if - refresh tokens are enabled on your FusionAuth instance. +- `app.rt` - a [Refresh + Token](https://fusionauth.io/docs/v1/tech/oauth/tokens#refresh-token) + used to obtain a new `app.at`. This cookie will only be set if + refresh tokens are enabled on your FusionAuth instance. The access token can be presented to APIs to authorize the request and the refresh token can be used to get a new access token. There are 2 ways to interact with this SDK: + 1. By hosting your own server that performs the OAuth token exchange and meets the [server code requirements for FusionAuth Web SDKs](https://github.com/FusionAuth/fusionauth-javascript-sdk-express#server-code-requirements). 2. By using the server hosted on your FusionAuth instance, i.e., not writing your own server code. @@ -63,6 +65,12 @@ compliant identity server. ## Getting Started +If you are new to Vue development, you may want to start with the Quickstart guide. If you are already familiar with Vue development, skip to the Installation section. + +### Quickstart + +See the [FusionAuth Vue Quickstart](https://fusionauth.io/docs/quickstarts/quickstart-javascript-vue-web) for a full tutorial on using FusionAuth and Vue. + ### Installation NPM: @@ -85,21 +93,24 @@ Configure and initialize the `FusionAuthVuePlugin` when you create your Vue app: ```typescript import { createApp } from 'vue'; -import FusionAuthVuePlugin, { type FusionAuthConfig } from '@fusionauth/vue-sdk'; +import FusionAuthVuePlugin, { + type FusionAuthConfig, +} from '@fusionauth/vue-sdk'; const config: FusionAuthConfig = { - clientId: "", // Your app's FusionAuth client id - serverUrl: "", // The url of the server that performs the token exchange - redirectUri: "", // The URI that the user is directed to after the login/register/logout action + clientId: '', // Your app's FusionAuth client id + serverUrl: '', // The url of the server that performs the token exchange + redirectUri: '', // The URI that the user is directed to after the login/register/logout action shouldAutoFetchUserInfo: true, // Automatically fetch userInfo when logged in. Defaults to false. shouldAutoRefresh: true, // Enables automatic token refresh. Defaults to false. - onRedirect: (state?: string) => { }, // Optional callback invoked upon redirect back from login or register. -} + onRedirect: (state?: string) => {}, // Optional callback invoked upon redirect back from login or register. + // useDpop: true, // Opt-in to DPoP mode. See "DPoP Mode" below. Defaults to false. +}; const app = createApp(App); app.use(FusionAuthVuePlugin, config); -app.mount('#app') +app.mount('#app'); ``` If you want to use the pre-styled buttons, don't forget to import the css file: @@ -130,13 +141,13 @@ Using `createFusionAuth`, the SDK can be configured more flexibly. ```typescript export default defineNuxtPlugin({ setup(nuxtApp) { - const fusionauth = createFusionAuth(config); - nuxtApp.vueApp.use(FusionAuthVuePlugin, { instance: fusionauth }) + const fusionauth = createFusionAuth(config); + nuxtApp.vueApp.use(FusionAuthVuePlugin, { instance: fusionauth }); return { - provide: { fusionauth } + provide: { fusionauth }, }; }, -}) +}); ``` ### `useFusionAuth` composable @@ -146,33 +157,23 @@ View the [full API documentation](https://github.com/FusionAuth/fusionauth-javas ```html