Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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