{{ idTokenClaims | json }}
- Zugangstoken: {{ accessToken }}
- - -{{ claims | json }}
+}
```
### Zusätzliche Ansprüche anfordern \{#request-additional-claims}
-{{ error.message }}
+ } @else { +Anmeldung wird abgeschlossen...
+ } + `, +}) +export class CallbackComponent { + readonly logto = inject(LogtoService); + + constructor() { + afterNextRender(() => { + void (async () => { + const callbackUri = window.location.href; + + if (!(await this.logto.isSignInRedirected(callbackUri))) { + window.location.replace(window.location.origin); + return; + } + + await this.logto.handleSignInCallback(callbackUri); + })().catch(() => { + // Das SDK gibt Callback-Fehler über logto.error() für das Template aus. + }); + }); + } +} +``` -```ts title="app/app.config.ts" -export const appConfig: ApplicationConfig = { - providers: [ - provideAuth({ - config: buildAngularAuthConfig({ - // ...andere Konfigurationen - // highlight-start - redirectUri: 'http://localhost:3000/callback', - postLogoutRedirectUri: 'http://localhost:3000/', - // highlight-end - }), - }), - // ...andere Provider - ], -}; +`isSignInRedirected()` prüft, ob die URL zu einer aktiven Anmeldesitzung passt. Wenn jemand die Callback-Route ohne eine solche Sitzung aufruft, leitet dieses Beispiel stattdessen auf die Startseite der Anwendung zurück, anstatt die Anmeldung abzuschließen. + +Registriere die Callback-Route in `app.routes.ts`. Sie muss mit dem Pfad deiner Redirect-URI übereinstimmen und darf keine Authentifizierung erfordern. Verwende zum Beispiel `callback` für eine Redirect-URI, die mit `/callback` endet: + +```ts title="app/app.routes.ts" +// Registrierung der Callback-Route +import { type Routes } from '@angular/router'; + +import { CallbackComponent } from './callback.component'; + +export const routes: Routes = [ + { path: 'callback', component: CallbackComponent }, + // ...weitere Routen +]; ``` -### Anmeldung und Abmeldung implementieren \{#implement-sign-in-and-sign-out} +Die Root-Komponente benötigt ein `{{ error.message }}
+} @if (logto.isLoading()) { +Lädt...
+} @else if (logto.isAuthenticated()) { + +} @else { + +} + +{{ error.message }}
+ } + @if (logto.isAuthenticated()) { + +{{ accessToken() }}
+ }
+ `,
+})
+export class ApiResourceComponent {
+ readonly logto = inject(LogtoService);
+ readonly accessToken = signal('');
+
+ async loadAccessToken() {
+ this.accessToken.set(await this.logto.getAccessToken('https://shopping.your-app.com/api'));
+ }
+}
+```
diff --git a/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
new file mode 100644
index 00000000000..68db1b56cbb
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
@@ -0,0 +1,59 @@
+```ts title="app/organizations.component.ts"
+import { Component, effect, inject, signal } from '@angular/core';
+import { LogtoService } from '@logto/angular';
+
+@Component({
+ selector: 'app-organizations',
+ standalone: true,
+ template: `
+ @if (logto.error(); as error) {
+ {{ error.message }}
+ } + @if (logto.isAuthenticated()) { +{{ organizationToken() }}
+ }
+ `,
+})
+export class OrganizationsComponent {
+ readonly logto = inject(LogtoService);
+ readonly organizationIds = signal{{ idTokenClaims | json }}
- Access token: {{ accessToken }}
- - -{{ claims | json }}
+}
```
### Solicitar reclamos adicionales \{#request-additional-claims}
-{{ error.message }}
+ } @else { +Completando el inicio de sesión...
+ } + `, +}) +export class CallbackComponent { + readonly logto = inject(LogtoService); + + constructor() { + afterNextRender(() => { + void (async () => { + const callbackUri = window.location.href; + + if (!(await this.logto.isSignInRedirected(callbackUri))) { + window.location.replace(window.location.origin); + return; + } + + await this.logto.handleSignInCallback(callbackUri); + })().catch(() => { + // El SDK expone los errores del callback a través de logto.error() para la plantilla. + }); + }); + } +} +``` -```ts title="app/app.config.ts" -export const appConfig: ApplicationConfig = { - providers: [ - provideAuth({ - config: buildAngularAuthConfig({ - // ...otras configuraciones - // highlight-start - redirectUri: 'http://localhost:3000/callback', - postLogoutRedirectUri: 'http://localhost:3000/', - // highlight-end - }), - }), - // ...otros proveedores - ], -}; +`isSignInRedirected()` verifica si la URL coincide con una sesión de inicio de sesión activa. Si alguien visita la ruta de callback sin una sesión activa, este ejemplo lo devuelve a la página principal de la aplicación en lugar de intentar completar el inicio de sesión. + +Registra la ruta de callback en `app.routes.ts`. Debe coincidir con la ruta de tu URI de redirección y no debe requerir autenticación. Por ejemplo, usa `callback` para una URI de redirección que termine en `/callback`: + +```ts title="app/app.routes.ts" +import { type Routes } from '@angular/router'; + +import { CallbackComponent } from './callback.component'; + +export const routes: Routes = [ + { path: 'callback', component: CallbackComponent }, + // ...otras rutas +]; ``` -### Implementar inicio y cierre de sesión \{#implement-sign-in-and-sign-out} +El componente raíz necesita un `{{ error.message }}
+} @if (logto.isLoading()) { +Cargando...
+} @else if (logto.isAuthenticated()) { + +} @else { + +} + +{{ error.message }}
+ } + @if (logto.isAuthenticated()) { + +{{ accessToken() }}
+ }
+ `,
+})
+export class ApiResourceComponent {
+ readonly logto = inject(LogtoService);
+ readonly accessToken = signal('');
+
+ async loadAccessToken() {
+ this.accessToken.set(await this.logto.getAccessToken('https://shopping.your-app.com/api'));
+ }
+}
+```
diff --git a/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
new file mode 100644
index 00000000000..ec67cf42537
--- /dev/null
+++ b/i18n/es/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
@@ -0,0 +1,59 @@
+```ts title="app/organizations.component.ts"
+import { Component, effect, inject, signal } from '@angular/core';
+import { LogtoService } from '@logto/angular';
+
+@Component({
+ selector: 'app-organizations',
+ standalone: true,
+ template: `
+ @if (logto.error(); as error) {
+ {{ error.message }}
+ } + @if (logto.isAuthenticated()) { +{{ organizationToken() }}
+ }
+ `,
+})
+export class OrganizationsComponent {
+ readonly logto = inject(LogtoService);
+ readonly organizationIds = signal{{ idTokenClaims | json }}
- Access token: {{ accessToken }}
- - -{{ claims | json }}
+}
```
### Demander des revendications supplémentaires \{#request-additional-claims}
-{{ error.message }}
+ } @else { +Finalisation de la connexion...
+ } + `, +}) +export class CallbackComponent { + readonly logto = inject(LogtoService); + + constructor() { + afterNextRender(() => { + void (async () => { + const callbackUri = window.location.href; + + if (!(await this.logto.isSignInRedirected(callbackUri))) { + window.location.replace(window.location.origin); + return; + } + + await this.logto.handleSignInCallback(callbackUri); + })().catch(() => { + // Le SDK expose les erreurs de callback via logto.error() pour le template. + }); + }); + } +} +``` -```ts title="app/app.config.ts" -export const appConfig: ApplicationConfig = { - providers: [ - provideAuth({ - config: buildAngularAuthConfig({ - // ...other config - // highlight-start - redirectUri: 'http://localhost:3000/callback', - postLogoutRedirectUri: 'http://localhost:3000/', - // highlight-end - }), - }), - // ...other providers - ], -}; +`isSignInRedirected()` vérifie si l'URL correspond à une session de connexion active. Si quelqu'un visite la route de callback sans session, cet exemple le renvoie à la page d'accueil de l'application au lieu de tenter de finaliser la connexion. + +Enregistrez la route de callback dans `app.routes.ts`. Elle doit correspondre au chemin de votre URI de redirection et ne doit pas nécessiter d'authentification. Par exemple, utilisez `callback` pour une URI de redirection se terminant par `/callback` : + +```ts title="app/app.routes.ts" +import { type Routes } from '@angular/router'; + +import { CallbackComponent } from './callback.component'; + +export const routes: Routes = [ + { path: 'callback', component: CallbackComponent }, + // ...autres routes +]; ``` -### Implémenter la connexion et la déconnexion \{#implement-sign-in-and-sign-out} +Le composant racine doit contenir un `{{ error.message }}
+} @if (logto.isLoading()) { +Chargement…
+} @else if (logto.isAuthenticated()) { + +} @else { + +} + +{{ error.message }}
+ } + @if (logto.isAuthenticated()) { + +{{ accessToken() }}
+ }
+ `,
+})
+export class ApiResourceComponent {
+ readonly logto = inject(LogtoService);
+ readonly accessToken = signal('');
+
+ async loadAccessToken() {
+ this.accessToken.set(await this.logto.getAccessToken('https://shopping.your-app.com/api'));
+ }
+}
+```
diff --git a/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
new file mode 100644
index 00000000000..ee020b79d56
--- /dev/null
+++ b/i18n/fr/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
@@ -0,0 +1,59 @@
+```ts title="app/organizations.component.ts"
+import { Component, effect, inject, signal } from '@angular/core';
+import { LogtoService } from '@logto/angular';
+
+@Component({
+ selector: 'app-organizations',
+ standalone: true,
+ template: `
+ @if (logto.error(); as error) {
+ {{ error.message }}
+ } + @if (logto.isAuthenticated()) { +{{ organizationToken() }}
+ }
+ `,
+})
+export class OrganizationsComponent {
+ readonly logto = inject(LogtoService);
+ readonly organizationIds = signal{{ idTokenClaims | json }}
- Access token: {{ accessToken }}
- - -{{ claims | json }}
+}
```
-### 追加のクレームをリクエストする \{#request-additional-claims}
+### 追加のクレーム (Claims) をリクエストする \{#request-additional-claims}
-{{ error.message }}
+ } @else { +サインインを完了しています...
+ } + `, +}) +export class CallbackComponent { + readonly logto = inject(LogtoService); + + constructor() { + afterNextRender(() => { + void (async () => { + const callbackUri = window.location.href; + + if (!(await this.logto.isSignInRedirected(callbackUri))) { + window.location.replace(window.location.origin); + return; + } + + await this.logto.handleSignInCallback(callbackUri); + })().catch(() => { + // SDK はコールバックエラーを logto.error() 経由でテンプレートに公開します。 + }); + }); + } +} +``` -```ts title="app/app.config.ts" -export const appConfig: ApplicationConfig = { - providers: [ - provideAuth({ - config: buildAngularAuthConfig({ - // ...他の設定 - // highlight-start - redirectUri: 'http://localhost:3000/callback', - postLogoutRedirectUri: 'http://localhost:3000/', - // highlight-end - }), - }), - // ...他のプロバイダー - ], -}; +`isSignInRedirected()` は、URL がアクティブなサインインセッションと一致するかどうかを確認します。誰かがセッションなしでコールバックルートにアクセスした場合、この例ではサインインを試みる代わりにアプリケーションのホームページへ戻します。 + +`app.routes.ts` でコールバックルートを登録します。これはリダイレクト URI のパスと一致し、認証 (Authentication) を必要としない必要があります。たとえば、リダイレクト URI が `/callback` で終わる場合は `callback` を使用します: + +```ts title="app/app.routes.ts" +import { type Routes } from '@angular/router'; + +import { CallbackComponent } from './callback.component'; + +export const routes: Routes = [ + { path: 'callback', component: CallbackComponent }, + // ...other routes +]; ``` -### サインインとサインアウトの実装 \{#implement-sign-in-and-sign-out} +ルートコンポーネントには、このルートをレンダリングするために `{{ error.message }}
+} @if (logto.isLoading()) { +読み込み中...
+} @else if (logto.isAuthenticated()) { + +} @else { + +} + +{{ error.message }}
+ } + @if (logto.isAuthenticated()) { + +{{ accessToken() }}
+ }
+ `,
+})
+export class ApiResourceComponent {
+ readonly logto = inject(LogtoService);
+ readonly accessToken = signal('');
+
+ async loadAccessToken() {
+ this.accessToken.set(await this.logto.getAccessToken('https://shopping.your-app.com/api'));
+ }
+}
+```
diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
new file mode 100644
index 00000000000..8971e7f66b3
--- /dev/null
+++ b/i18n/ja/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
@@ -0,0 +1,59 @@
+```ts title="app/organizations.component.ts"
+import { Component, effect, inject, signal } from '@angular/core';
+import { LogtoService } from '@logto/angular';
+
+@Component({
+ selector: 'app-organizations',
+ standalone: true,
+ template: `
+ @if (logto.error(); as error) {
+ {{ error.message }}
+ } + @if (logto.isAuthenticated()) { +{{ organizationToken() }}
+ }
+ `,
+})
+export class OrganizationsComponent {
+ readonly logto = inject(LogtoService);
+ readonly organizationIds = signal{{ idTokenClaims | json }}
- Access token: {{ accessToken }}
- - -{{ claims | json }}
+}
```
-### 추가 클레임 요청 \{#request-additional-claims}
+### 추가 클레임 (Claim) 요청하기 \{#request-additional-claims}
-{{ error.message }}
+ } @else { +로그인 완료 중...
+ } + `, +}) +export class CallbackComponent { + readonly logto = inject(LogtoService); + + constructor() { + afterNextRender(() => { + void (async () => { + const callbackUri = window.location.href; + + if (!(await this.logto.isSignInRedirected(callbackUri))) { + window.location.replace(window.location.origin); + return; + } + + await this.logto.handleSignInCallback(callbackUri); + })().catch(() => { + // SDK는 콜백 오류를 템플릿에서 logto.error()로 노출합니다. + }); + }); + } +} +``` -```ts title="app/app.config.ts" -export const appConfig: ApplicationConfig = { - providers: [ - provideAuth({ - config: buildAngularAuthConfig({ - // ...other config - // highlight-start - redirectUri: 'http://localhost:3000/callback', - postLogoutRedirectUri: 'http://localhost:3000/', - // highlight-end - }), - }), - // ...other providers - ], -}; +`isSignInRedirected()`는 URL이 활성 로그인 세션과 일치하는지 확인합니다. 누군가 세션 없이 콜백 라우트를 방문하면, 이 예제는 로그인 완료를 시도하는 대신 애플리케이션 홈 페이지로 돌려보냅니다. + +`app.routes.ts`에 콜백 라우트를 등록하세요. 이 경로는 리디렉션 URI의 경로와 일치해야 하며, 인증이 필요하지 않아야 합니다. 예를 들어, 리디렉션 URI가 `/callback`으로 끝난다면 `callback`을 사용하세요: + +```ts title="app/app.routes.ts" +import { type Routes } from '@angular/router'; + +import { CallbackComponent } from './callback.component'; + +export const routes: Routes = [ + { path: 'callback', component: CallbackComponent }, + // ...other routes +]; ``` -### 로그인 및 로그아웃 구현 \{#implement-sign-in-and-sign-out} +루트 컴포넌트에는 다음 단계에서 보여주는 것처럼 이 라우트를 렌더링하기 위해 `{{ error.message }}
+} @if (logto.isLoading()) { +로딩 중...
+} @else if (logto.isAuthenticated()) { + +} @else { + +} + +{{ error.message }}
+ } + @if (logto.isAuthenticated()) { + +{{ accessToken() }}
+ }
+ `,
+})
+export class ApiResourceComponent {
+ readonly logto = inject(LogtoService);
+ readonly accessToken = signal('');
+
+ async loadAccessToken() {
+ this.accessToken.set(await this.logto.getAccessToken('https://shopping.your-app.com/api'));
+ }
+}
+```
diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md b/i18n/ko/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
new file mode 100644
index 00000000000..61a79ea86de
--- /dev/null
+++ b/i18n/ko/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
@@ -0,0 +1,59 @@
+```ts title="app/organizations.component.ts"
+import { Component, effect, inject, signal } from '@angular/core';
+import { LogtoService } from '@logto/angular';
+
+@Component({
+ selector: 'app-organizations',
+ standalone: true,
+ template: `
+ @if (logto.error(); as error) {
+ {{ error.message }}
+ } + @if (logto.isAuthenticated()) { +{{ organizationToken() }}
+ }
+ `,
+})
+export class OrganizationsComponent {
+ readonly logto = inject(LogtoService);
+ readonly organizationIds = signal{{ idTokenClaims | json }}
- Access token: {{ accessToken }}
- - -{{ claims | json }}
+}
```
### Solicitar reivindicações adicionais \{#request-additional-claims}
-{{ error.message }}
+ } @else { +Completando o login...
+ } + `, +}) +export class CallbackComponent { + readonly logto = inject(LogtoService); + + constructor() { + afterNextRender(() => { + void (async () => { + const callbackUri = window.location.href; + + if (!(await this.logto.isSignInRedirected(callbackUri))) { + window.location.replace(window.location.origin); + return; + } + + await this.logto.handleSignInCallback(callbackUri); + })().catch(() => { + // O SDK expõe erros de callback através de logto.error() para o template. + }); + }); + } +} +``` -Como usamos `http://localhost:3000/callback` como o URI de redirecionamento, agora precisamos lidar com isso adequadamente. A biblioteca `angular-auth-oidc-client` fornece suporte embutido para lidar com o redirecionamento. Você pode simplesmente configurar os configs do provedor de autenticação corretamente e a biblioteca cuidará do resto. +`isSignInRedirected()` verifica se a URL corresponde a uma sessão de login ativa. Se alguém acessar a rota de callback sem uma sessão, este exemplo o retorna para a página inicial do aplicativo em vez de tentar completar o login. -```ts title="app/app.config.ts" -export const appConfig: ApplicationConfig = { - providers: [ - provideAuth({ - config: buildAngularAuthConfig({ - // ...outras configurações - // highlight-start - redirectUri: 'http://localhost:3000/callback', - postLogoutRedirectUri: 'http://localhost:3000/', - // highlight-end - }), - }), - // ...outros provedores - ], -}; +Registre a rota de callback em `app.routes.ts`. Ela deve corresponder ao caminho do seu URI de redirecionamento e não deve exigir autenticação. Por exemplo, use `callback` para um URI de redirecionamento terminando em `/callback`: + +```ts title="app/app.routes.ts" +// Exemplo de rota de callback para autenticação Logto +import { type Routes } from '@angular/router'; + +import { CallbackComponent } from './callback.component'; + +export const routes: Routes = [ + { path: 'callback', component: CallbackComponent }, + // ...outras rotas +]; ``` -### Implementar login e logout \{#implement-sign-in-and-sign-out} +O componente raiz precisa de um `{{ error.message }}
+} @if (logto.isLoading()) { +Carregando...
+} @else if (logto.isAuthenticated()) { + +} @else { + +} + +{{ error.message }}
+ } + @if (logto.isAuthenticated()) { + +{{ accessToken() }}
+ }
+ `,
+})
+export class ApiResourceComponent {
+ readonly logto = inject(LogtoService);
+ readonly accessToken = signal('');
+
+ async loadAccessToken() {
+ this.accessToken.set(await this.logto.getAccessToken('https://shopping.your-app.com/api'));
+ }
+}
+```
diff --git a/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
new file mode 100644
index 00000000000..e76af2e8f82
--- /dev/null
+++ b/i18n/pt-BR/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
@@ -0,0 +1,59 @@
+```ts title="app/organizations.component.ts"
+import { Component, effect, inject, signal } from '@angular/core';
+import { LogtoService } from '@logto/angular';
+
+@Component({
+ selector: 'app-organizations',
+ standalone: true,
+ template: `
+ @if (logto.error(); as error) {
+ {{ error.message }}
+ } + @if (logto.isAuthenticated()) { +{{ organizationToken() }}
+ }
+ `,
+})
+export class OrganizationsComponent {
+ readonly logto = inject(LogtoService);
+ readonly organizationIds = signal{{ idTokenClaims | json }}
- Access token: {{ accessToken }}
- - -{{ claims | json }}
+}
```
-### ขอการอ้างสิทธิ์เพิ่มเติม \{#request-additional-claims}
+### ขอ การอ้างสิทธิ์ (claims) เพิ่มเติม \{#request-additional-claims}
-{{ error.message }}
+ } @else { +กำลังดำเนินการลงชื่อเข้าใช้...
+ } + `, +}) +export class CallbackComponent { + readonly logto = inject(LogtoService); + + constructor() { + afterNextRender(() => { + void (async () => { + const callbackUri = window.location.href; + + if (!(await this.logto.isSignInRedirected(callbackUri))) { + window.location.replace(window.location.origin); + return; + } + + await this.logto.handleSignInCallback(callbackUri); + })().catch(() => { + // SDK จะส่งข้อผิดพลาด callback ผ่าน logto.error() สำหรับใช้ใน template + }); + }); + } +} +``` -```ts title="app/app.config.ts" -export const appConfig: ApplicationConfig = { - providers: [ - provideAuth({ - config: buildAngularAuthConfig({ - // ...other config - // highlight-start - redirectUri: 'http://localhost:3000/callback', - postLogoutRedirectUri: 'http://localhost:3000/', - // highlight-end - }), - }), - // ...other providers - ], -}; +`isSignInRedirected()` จะตรวจสอบว่า URL ตรงกับเซสชันการลงชื่อเข้าใช้ที่กำลังดำเนินการอยู่หรือไม่ หากมีผู้เข้าชมเส้นทาง callback โดยไม่มีเซสชันนี้ ตัวอย่างนี้จะนำผู้ใช้งานกลับไปยังหน้าแรกของแอปพลิเคชันแทนที่จะพยายามดำเนินการลงชื่อเข้าใช้ให้สมบูรณ์ + +ลงทะเบียนเส้นทาง callback ใน `app.routes.ts` โดยต้องตรงกับ path ของ redirect URI และต้องไม่ต้องการการยืนยันตัวตน ตัวอย่างเช่น ใช้ `callback` สำหรับ redirect URI ที่ลงท้ายด้วย `/callback`: + +```ts title="app/app.routes.ts" +import { type Routes } from '@angular/router'; + +import { CallbackComponent } from './callback.component'; + +export const routes: Routes = [ + { path: 'callback', component: CallbackComponent }, + // ...other routes +]; ``` -### สร้างฟังก์ชัน sign-in และ sign-out \{#implement-sign-in-and-sign-out} +คอมโพเนนต์ root ต้องมี `{{ error.message }}
+} @if (logto.isLoading()) { +กำลังโหลด...
+} @else if (logto.isAuthenticated()) { + +} @else { + +} + +{{ error.message }}
+ } + @if (logto.isAuthenticated()) { + +{{ accessToken() }}
+ }
+ `,
+})
+export class ApiResourceComponent {
+ readonly logto = inject(LogtoService);
+ readonly accessToken = signal('');
+
+ async loadAccessToken() {
+ this.accessToken.set(await this.logto.getAccessToken('https://shopping.your-app.com/api'));
+ }
+}
+```
diff --git a/i18n/th/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md b/i18n/th/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
new file mode 100644
index 00000000000..641730314fa
--- /dev/null
+++ b/i18n/th/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
@@ -0,0 +1,59 @@
+```ts title="app/organizations.component.ts"
+import { Component, effect, inject, signal } from '@angular/core';
+import { LogtoService } from '@logto/angular';
+
+@Component({
+ selector: 'app-organizations',
+ standalone: true,
+ template: `
+ @if (logto.error(); as error) {
+ {{ error.message }}
+ } + @if (logto.isAuthenticated()) { +{{ organizationToken() }}
+ }
+ `,
+})
+export class OrganizationsComponent {
+ readonly logto = inject(LogtoService);
+ readonly organizationIds = signal{{ idTokenClaims | json }}
- Access token: {{ accessToken }}
- - -{{ claims | json }}
+}
```
-### 请求额外的声明 \{#request-additional-claims}
+### 请求额外声明 (Claims) \{#request-additional-claims}
-{{ error.message }}
+ } @else { +正在完成登录...
+ } + `, +}) +export class CallbackComponent { + readonly logto = inject(LogtoService); + + constructor() { + afterNextRender(() => { + void (async () => { + const callbackUri = window.location.href; + + if (!(await this.logto.isSignInRedirected(callbackUri))) { + window.location.replace(window.location.origin); + return; + } + + await this.logto.handleSignInCallback(callbackUri); + })().catch(() => { + // SDK 会通过 logto.error() 向模板暴露回调错误。 + }); + }); + } +} +``` -```ts title="app/app.config.ts" -export const appConfig: ApplicationConfig = { - providers: [ - provideAuth({ - config: buildAngularAuthConfig({ - // ...other config - // highlight-start - redirectUri: 'http://localhost:3000/callback', - postLogoutRedirectUri: 'http://localhost:3000/', - // highlight-end - }), - }), - // ...other providers - ], -}; +`isSignInRedirected()` 用于检查当前 URL 是否匹配一个活跃的登录会话。如果有人在没有登录会话的情况下访问回调路由,本示例会将其重定向回应用首页,而不是尝试完成登录。 + +在 `app.routes.ts` 中注册回调路由。它必须与重定向 URI 的路径一致,并且不能要求认证 (Authentication)。例如,重定向 URI 以 `/callback` 结尾时,使用 `callback`: + +```ts title="app/app.routes.ts" +import { type Routes } from '@angular/router'; + +import { CallbackComponent } from './callback.component'; + +export const routes: Routes = [ + { path: 'callback', component: CallbackComponent }, + // ...other routes +]; ``` -### 实现登录和登出 \{#implement-sign-in-and-sign-out} +根组件需要一个 `{{ error.message }}
+} @if (logto.isLoading()) { +加载中...
+} @else if (logto.isAuthenticated()) { + +} @else { + +} + +{{ error.message }}
+ } + @if (logto.isAuthenticated()) { + +{{ accessToken() }}
+ }
+ `,
+})
+export class ApiResourceComponent {
+ readonly logto = inject(LogtoService);
+ readonly accessToken = signal('');
+
+ async loadAccessToken() {
+ this.accessToken.set(await this.logto.getAccessToken('https://shopping.your-app.com/api'));
+ }
+}
+```
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
new file mode 100644
index 00000000000..d1e7274b86d
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
@@ -0,0 +1,59 @@
+```ts title="app/organizations.component.ts"
+import { Component, effect, inject, signal } from '@angular/core';
+import { LogtoService } from '@logto/angular';
+
+@Component({
+ selector: 'app-organizations',
+ standalone: true,
+ template: `
+ @if (logto.error(); as error) {
+ {{ error.message }}
+ } + @if (logto.isAuthenticated()) { +{{ organizationToken() }}
+ }
+ `,
+})
+export class OrganizationsComponent {
+ readonly logto = inject(LogtoService);
+ readonly organizationIds = signal{{ idTokenClaims | json }}
- Access token: {{ accessToken }}
- - -{{ claims | json }}
+}
```
-### 請求額外的宣告 \{#request-additional-claims}
+### 請求額外宣告 (claims) \{#request-additional-claims}
-{{ error.message }}
+ } @else { +正在完成登入...
+ } + `, +}) +export class CallbackComponent { + readonly logto = inject(LogtoService); + + constructor() { + afterNextRender(() => { + void (async () => { + const callbackUri = window.location.href; + + if (!(await this.logto.isSignInRedirected(callbackUri))) { + window.location.replace(window.location.origin); + return; + } + + await this.logto.handleSignInCallback(callbackUri); + })().catch(() => { + // SDK 會透過 logto.error() 將 callback 錯誤暴露給模板。 + }); + }); + } +} +``` -由於我們使用 `http://localhost:3000/callback` 作為重定向 URI,現在需要妥善處理它。`angular-auth-oidc-client` 函式庫提供了內建的重定向處理支援。你只需正確配置驗證提供者的設定,函式庫會處理其餘部分。 +`isSignInRedirected()` 用來檢查 URL 是否符合有效的登入階段。如果有人在沒有登入階段的情況下訪問 callback 路由,此範例會將他們導回應用程式首頁,而不是嘗試完成登入。 -```ts title="app/app.config.ts" -export const appConfig: ApplicationConfig = { - providers: [ - provideAuth({ - config: buildAngularAuthConfig({ - // ...其他設定 - // highlight-start - redirectUri: 'http://localhost:3000/callback', - postLogoutRedirectUri: 'http://localhost:3000/', - // highlight-end - }), - }), - // ...其他提供者 - ], -}; +在 `app.routes.ts` 註冊 callback 路由。它必須與你的 redirect URI 路徑一致,且不能要求驗證。例如,若 redirect URI 以 `/callback` 結尾,則使用 `callback`: + +```ts title="app/app.routes.ts" +import { type Routes } from '@angular/router'; + +import { CallbackComponent } from './callback.component'; + +export const routes: Routes = [ + { path: 'callback', component: CallbackComponent }, + // ...other routes +]; ``` -### 實作登入與登出 \{#implement-sign-in-and-sign-out} +根元件需要 `{{ error.message }}
+} @if (logto.isLoading()) { +載入中...
+} @else if (logto.isAuthenticated()) { + +} @else { + +} + +{{ error.message }}
+ } + @if (logto.isAuthenticated()) { + +{{ accessToken() }}
+ }
+ `,
+})
+export class ApiResourceComponent {
+ readonly logto = inject(LogtoService);
+ readonly accessToken = signal('');
+
+ async loadAccessToken() {
+ this.accessToken.set(await this.logto.getAccessToken('https://shopping.your-app.com/api'));
+ }
+}
+```
diff --git a/i18n/zh-TW/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md b/i18n/zh-TW/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
new file mode 100644
index 00000000000..ee2421cb412
--- /dev/null
+++ b/i18n/zh-TW/docusaurus-plugin-content-docs/current/quick-starts/framework/angular/code/_get-organization-access-token-code.md
@@ -0,0 +1,59 @@
+```ts title="app/organizations.component.ts"
+import { Component, effect, inject, signal } from '@angular/core';
+import { LogtoService } from '@logto/angular';
+
+@Component({
+ selector: 'app-organizations',
+ standalone: true,
+ template: `
+ @if (logto.error(); as error) {
+ {{ error.message }}
+ } + @if (logto.isAuthenticated()) { +{{ organizationToken() }}
+ }
+ `,
+})
+export class OrganizationsComponent {
+ readonly logto = inject(LogtoService);
+ readonly organizationIds = signal