Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions docs/quick-starts/framework/angular/README.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
slug: /quick-starts/angular
sidebar_label: Angular
sidebar_custom_props:
description: Angular is a JavaScript library for building user interfaces.
description: Angular is a framework for building web applications.
---

import FurtherReadings from '../../fragments/_further-readings.md';
Expand All @@ -15,12 +15,15 @@ import Integration from './_integration.mdx';

# Add authentication to your Angular application

This guide will show you how to integrate Logto Angular SDK v2 into your application.

<GuideTip />

## Prerequisites \{#prerequisites}

- A [Logto Cloud](https://cloud.logto.io) account or a [self-hosted Logto](/introduction/set-up-logto-oss).
- A Logto single-page application created.
- A single-page application (SPA) created in Logto Console.
- An Angular 20 project.

## Installation \{#installation}

Expand Down
59 changes: 52 additions & 7 deletions docs/quick-starts/framework/angular/_api-resources.mdx
Original file line number Diff line number Diff line change
@@ -1,22 +1,67 @@
import ApiResourcesDescription from '../../fragments/_api-resources-description.md';
import ConfigApiResources from '../../fragments/_config-api-resources.mdx';
import FetchAccessTokenForApiResources from '../../fragments/_fetch-access-token-for-api-resources.mdx';
import FetchOrganizationTokenForUser from '../../fragments/_fetch-organization-token-for-user.mdx';

import ConfigOrganizationCode from './code/_config-organization-code.md';
import ConfigResourcesCode from './code/_config-resources-code.md';
import ConfigResourcesWithScopesCode from './code/_config-resources-with-scopes-code.md';

### Configure `angular-auth-oidc-client` for API resource \{#configure-angular-auth-oidc-client-for-api-resource}
import ConfigResourcesWithSharedScopesCode from './code/_config-resources-with-shared-scopes-code.md';
import GetAccessTokenCode from './code/_get-access-token-code.md';
import GetOrganizationAccessTokenCode from './code/_get-organization-access-token-code.md';

<ApiResourcesDescription />

### Configure Logto client \{#configure-logto-client}

<ConfigApiResources
configResourcesCode={<ConfigResourcesCode />}
configResourcesWithScopesCode={<ConfigResourcesWithScopesCode />}
configResourcesWithSharedScopesCode={<ConfigResourcesWithSharedScopesCode />}
/>

Now, the access token will be in the JSON Web Token (JWT) format instead of a random string (opaque token).
Sign in again after changing the resources or scopes so the user can authorize the updated configuration.

:::warning
Both `autoUserInfo` and `renewUserInfoAfterTokenRenew` will be disabled when `resource` is set. This is because the access token will be requested for the specific API resource and not for the user info endpoint.
:::
### Fetch access token for the API resource \{#fetch-access-token-for-the-api-resource}

<FetchAccessTokenForApiResources
getAccessTokenApi="getAccessToken()"
getAccessTokenCode={<GetAccessTokenCode />}
/>

Use the exact resource identifier from your configuration. Call `getAccessToken(resource)` whenever you make an API request so the SDK can return a valid token, rather than keeping a token indefinitely in your component.

### Fetch organization tokens \{#fetch-organization-tokens}

<FetchOrganizationTokenForUser
organizationScope="UserScope.Organizations"
configOrganizationCode={<ConfigOrganizationCode />}
getOrganizationAccessTokenCode={<GetOrganizationAccessTokenCode />}
/>

Merge `UserScope.Organizations` with any existing scopes, and sign in again after updating the configuration. `getOrganizationToken(organizationId)` returns a token for the selected Logto organization; use `getAccessToken(resource)` for an API resource token.

### Attach access token to request headers \{#attach-access-token-to-request-headers}

Put the token in the `Authorization` HTTP header using the Bearer format (`Bearer YOUR_TOKEN`). For example, add this method to an authenticated component that injects `LogtoService`:

Currently, only Logto official SDKs support the ability to request both user info and API resource access tokens. If you need to request both, please do not hesitate to contact us.
```ts
async fetchProducts() {
const accessToken = await this.logto.getAccessToken('https://shopping.your-app.com/api');
const response = await fetch('https://shopping.your-app.com/api/products', {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});

if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}

return response.json();
}
```

:::note
The example uses `fetch`. If you use Angular `HttpClient`, set the same `Authorization` header in its request options.
:::
157 changes: 65 additions & 92 deletions docs/quick-starts/framework/angular/_get-user-information.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,132 +5,105 @@ import FindUserInfoMissing from '../../fragments/_find-user-info-missing.mdx';
import ScopesAndClaims from '../../fragments/_scopes-and-claims.mdx';
import ScopesAndClaimsIntroduction from '../../fragments/_scopes-claims-introduction.md';

Once the user has successfully signed in, Logto will issue an [ID token](https://openid.net/specs/openid-connect-core-1_0.html#IDToken) that contains the user information claims. The ID token is a JSON Web Token (JWT).

It's important to note that the user information claims that can be retrieved depending on the
scopes used by the user during signing-in, and considering performance and data size, the ID token
may not contain all user claims, some user claims are only available in the [userinfo endpoint](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo) (see
the related list below).

The `buildAngularAuthConfig()` utility will enable `autoUserInfo` and `renewUserInfoAfterTokenRenew` if there's no `resource` provided in the config. This means that Logto will automatically fetch the user information after the user signs in and renew the user information after the token is renewed.

:::info
To learn more about configuring the `angular-auth-oidc-client` library, see the [official documentation](https://angular-auth-oidc-client.com/).
:::

### Display user information \{#display-user-information}

The `OidcSecurityService` provides a convenient way to subscribe to the authentication state as well as user information:
To display the user's information, use `getIdTokenClaims()` to read claims from the ID token without an additional network request. Add an `effect` to your `AppComponent` to load the claims when `isAuthenticated()` becomes true, including when an existing session is restored. Import `JsonPipe` to display the result:

```ts title="app/app.component.ts"
import { OidcSecurityService } from 'angular-auth-oidc-client';
import { decodeIdToken, type IdTokenClaims } from '@logto/js';

export class AppComponent implements OnInit {
isAuthenticated = false;
idTokenClaims?: IdTokenClaims;
accessToken?: string;

constructor(public oidcSecurityService: OidcSecurityService) {}

ngOnInit() {
this.oidcSecurityService.checkAuth().subscribe(({ isAuthenticated, idToken, accessToken }) => {
console.log('app authenticated', isAuthenticated, idToken);
this.isAuthenticated = isAuthenticated;
this.idTokenClaims = decodeIdToken(idToken);
this.accessToken = accessToken;
import { JsonPipe } from '@angular/common';
import { Component, effect, inject, signal } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { LogtoService, type IdTokenClaims } from '@logto/angular';

@Component({
selector: 'app-root',
standalone: true,
imports: [JsonPipe, RouterOutlet],
templateUrl: './app.component.html',
})
export class AppComponent {
readonly logto = inject(LogtoService);
readonly user = signal<IdTokenClaims | undefined>(undefined);

constructor() {
effect(() => {
if (!this.logto.isAuthenticated()) {
this.user.set(undefined);
return;
}

void this.logto
.getIdTokenClaims()
.then((claims) => {
this.user.set(claims);
})
.catch(() => {
// The SDK exposes the error through logto.error() for the template.
});
});
}

// ...other methods
// ...keep the signIn() and signOut() methods from the previous step
}
```

And use it in the template:
Add the following inside the `logto.isAuthenticated()` branch of your template:

```html title="app/app.component.html"
<button *ngIf="!isAuthenticated" (click)="signIn()">Sign in</button>
<ng-container *ngIf="isAuthenticated">
<pre>{{ idTokenClaims | json }}</pre>
<p>Access token: {{ accessToken }}</p>
<!-- ... -->
<button (click)="signOut()">Sign out</button>
</ng-container>
@if (user(); as claims) {
<pre>{{ claims | json }}</pre>
}
```

### Request additional claims \{#request-additional-claims}

<FindUserInfoMissing method="idToken" />
<FindUserInfoMissing method="getIdTokenClaims()" />

<ScopesAndClaimsIntroduction />

To request additional scopes, you can configure the auth provider configs:
Add the scopes to your `provideLogto` configuration:

```tsx title="app/app.config.ts"
import { UserScope, buildAngularAuthConfig } from '@logto/js';
```ts title="app/app.config.ts"
import { type ApplicationConfig } from '@angular/core';
import { provideLogto, UserScope } from '@logto/angular';

export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(withFetch()),
provideAuth({
config: buildAngularAuthConfig({
// ...other configs
// highlight-start
scopes: [
UserScope.Email,
UserScope.Phone,
UserScope.CustomData,
UserScope.Identities,
UserScope.Organizations,
],
// highlight-end
}),
provideLogto({
endpoint: '<your-logto-endpoint>',
appId: '<your-app-id>',
scopes: [
UserScope.Email,
UserScope.Phone,
UserScope.CustomData,
UserScope.Identities,
UserScope.Organizations,
],
}),
// ...other providers
],
};
```

Then you can access the additional claims in the return value of `idToken`.
Sign in again after changing the scopes. The additional ID token claims, such as `email` and `phone_number`, will be available from `getIdTokenClaims()` and displayed by the example above.

{/* eslint-disable prettier/prettier */}
<ClaimsNeedNetworkRequest
type="option"
configOption="userData"
value="userData"
type="method"
method="fetchUserInfo()"
codeSnippet={
<CodeBlock language="ts" title="app/app.component.ts">{`import { OidcSecurityService } from 'angular-auth-oidc-client';
// highlight-next-line
import { type UserInfoResponse } from '@logto/js';

export class AppComponent implements OnInit {
isAuthenticated = false;
// highlight-next-line
userData?: UserInfoResponse;
accessToken?: string;

constructor(public oidcSecurityService: OidcSecurityService) {}

ngOnInit() {
this.oidcSecurityService
.checkAuth()
// highlight-next-line
.subscribe(({ isAuthenticated, userData, accessToken }) => {
console.log('app authenticated', isAuthenticated, idToken);
this.isAuthenticated = isAuthenticated;
// highlight-next-line
this.userData = userData;
this.accessToken = accessToken;
});
<CodeBlock
language="ts"
title="app/app.component.ts"
>{`// Add this method to AppComponent and call it after sign-in.
async loadUserInfo() {
const userInfo = await this.logto.fetchUserInfo();
// Now you can access userInfo.custom_data, userInfo.identities, etc.
return userInfo;
}`}</CodeBlock>
}

// ...other methods
}

// Now you can access the claim \`userData.custom_data\``}</CodeBlock>
}
/>
{/* eslint-enable prettier/prettier */}

`fetchUserInfo()` can be used alongside API resource access tokens. Configuring `resources` does not prevent the SDK from requesting user information.

### Scopes and claims \{#scopes-and-claims}

Expand Down
4 changes: 2 additions & 2 deletions docs/quick-starts/framework/angular/_guide-tip.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
:::tip

- The following demonstration is built on Angular 18.0.0 and [angular-auth-oidc-client](https://github.com/damienbod/angular-auth-oidc-client).
- The sample project is available in the [GitHub repository](https://github.com/logto-io/js/tree/master/packages/angular-sample).
- This guide uses the first-party `@logto/angular` v2 SDK, which supports Angular 20 and provides dependency injection and Signals.
- The sample project is available in our [SDK repository](https://github.com/logto-io/js/tree/master/packages/angular-sample).

:::
31 changes: 2 additions & 29 deletions docs/quick-starts/framework/angular/_installation.mdx
Original file line number Diff line number Diff line change
@@ -1,30 +1,3 @@
import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';
import NpmLikeInstallation from '../../fragments/_npm-like-installation.mdx';

Install Logto JS core SDK and Angular OIDC client library:

<Tabs>

<TabItem value="npm" label="npm">

```bash
npm i @logto/js angular-auth-oidc-client
```

</TabItem>
<TabItem value="pnpm" label="pnpm">

```bash
pnpm add @logto/js angular-auth-oidc-client
```

</TabItem>
<TabItem value="yarn" label="yarn">

```bash
yarn add @logto/js angular-auth-oidc-client
```

</TabItem>

</Tabs>
<NpmLikeInstallation packageName="@logto/angular" />
Loading
Loading