-
Notifications
You must be signed in to change notification settings - Fork 316
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4928 from sagara-gunathunga/master
- Loading branch information
Showing
21 changed files
with
932 additions
and
4 deletions.
There are no files selected for viewing
99 changes: 99 additions & 0 deletions
99
en/asgardeo/docs/complete-guides/javascript/accessing-protected-api.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
--- | ||
template: templates/complete-guide.html | ||
heading: Accessing protected API from your JavaScript app | ||
read_time: 2 min | ||
--- | ||
|
||
In this section, we will focus on how to call a secure API from your JavaScript app using the other token—the access token. | ||
|
||
For simplicity, let's assume that the APIs we’re calling are secured by the same Identity Provider (IdP) and use the same issuer— in this case, the same {{product_name}} organization. This is typical when JavaScript apps are interacting with internal APIs within the same organization. | ||
|
||
!!! tip "Tip" | ||
|
||
If your app needs to call APIs secured by a different IdP, you’ll need to exchange your current access token for a new one issued by the IdP securing those APIs. This can be done using the OAuth2 token exchange grant type or other supported grant types. We will cover these scenarios in a separate guide. | ||
|
||
## Using SDK Built-in HTTP client | ||
|
||
You can use the `httpRequest` API provided by the Asgardeo SDK to make HTTP requests to these endpoints. This method is used to send http requests to Asgardeo or desired backend. The developer doesn’t need to manually attach the access token since this method does it automatically. | ||
|
||
The following is a simple example of how you might use the Asgardeo SDK’s `httpRequest` to call a protected API endpoint, such as `/scim2/me` (to get the user profile details after signing in). In this case, the SCIM 2 endpoint is secured by the same {{product_name}} organization. {{product_name}} provides a SCIM 2 API for managing users within your organization. While user management with SCIM 2 is a topic for a different guide, we will use the API as part of our current guide. | ||
|
||
!!! note "Note" | ||
|
||
The storage type must be set to `webWorker` for the token to be automatically attached. If it’s set to `sessionStorage` or `localStorage`, you may implement your own function for attaching the access token to the network request. | ||
|
||
```javascript | ||
|
||
const requestConfig = { | ||
headers: { | ||
"Accept": "application/json", | ||
"Content-Type": "application/scim+json" | ||
}, | ||
method: "GET", | ||
url: "https://api.asgardeo.io/t/<your-organization-name>/scim2/me" | ||
}; | ||
|
||
|
||
auth.httpRequest(requestConfig).then((response) => { | ||
var req = response; | ||
console.log(response); | ||
}).catch((error) => { | ||
console.error(error); | ||
}); | ||
|
||
|
||
``` | ||
|
||
!!! Important | ||
|
||
Replace the `<your-organization-name>` placeholders in the above code with your registered organization name in Asgardeo. | ||
|
||
Note that you don’t need to manually specify the Authorization header under headers in requestConfig, as httpRequest method intercepts the request and attaches the access token to the network request as the Authorization header. | ||
|
||
In the above example, the final request config sent by the httpRequest method would be as follows. | ||
|
||
```javascript hl_lines="5" | ||
|
||
const requestConfig = { | ||
headers: { | ||
"Accept": "application/json", | ||
"Content-Type": "application/scim+json", | ||
"Authorization": "Bearer <access_token_retrieved_from_web_worker>" | ||
}, | ||
method: "GET", | ||
url: "https://api.asgardeo.io/t/<org_name>/scim2/me" | ||
}; | ||
|
||
``` | ||
|
||
In case you want to send multiple API requests in parallel, you can use the httpRequestAll method to simultaneously trigger parallel network requests and receive responses after all network requests are completed. | ||
|
||
The following code snippet shows a javascript method which accepts a list of application IDs and sends multiple network requests for each app ID in parallel. The responses will contain results for each id, as an array of responses. | ||
|
||
```javascript | ||
|
||
|
||
auth.httpRequestAll(configs).then((responses) => { | ||
response.forEach((response) => { | ||
console.log(response); | ||
}); | ||
}).catch((error) => { | ||
console.error(error); | ||
}); | ||
|
||
|
||
``` | ||
|
||
## Using a custom HTTP client | ||
|
||
In case you are not using the `webWorker` as the storage type, the `getAccessToken` method can be used to fetch the access token and manually attach it to the network request. The following is an example where the access token is fetched and manually attached to the authorization header of a Fetch request. | ||
|
||
```javascript | ||
|
||
auth.getAccessToken().then((token) => { | ||
console.log(token); | ||
}).error((error) => { | ||
console.error(error); | ||
}); | ||
|
||
``` |
106 changes: 106 additions & 0 deletions
106
en/asgardeo/docs/complete-guides/javascript/add-login-and-logout.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
--- | ||
template: templates/complete-guide.html | ||
heading: Add login and logout to your app | ||
read_time: 2 min | ||
--- | ||
|
||
Next, let’s add some code to implement login and logout links for our Javascript app. The `AsgardeoSPAClient` provides `signIn` and `signOut` methods and access to the authentication state. | ||
|
||
```javascript title="src/main.js" hl_lines="1 14-30 32-41 43-49" | ||
|
||
import { AsgardeoSPAClient, SPAUtils } from "@asgardeo/auth-spa"; | ||
|
||
const auth = AsgardeoSPAClient.getInstance(); | ||
|
||
await auth.initialize({ | ||
signInRedirectURL: "http://localhost:5173", | ||
signOutRedirectURL: "http://localhost:5173", | ||
clientID: "RNCTsWN50MyqiQpFuWFjifJdIcIa", | ||
baseUrl: "https://api.asgardeo.io/t/sagaraorg", | ||
scope: ["openid", "profile"] | ||
}); | ||
|
||
|
||
(async () => { | ||
let user = undefined; | ||
|
||
if (SPAUtils.hasAuthSearchParamsInURL()) { | ||
user = await auth.signIn({ callOnlyOnRedirect: true }); | ||
} else { | ||
user = await auth.trySignInSilently(); | ||
} | ||
|
||
if (user) { | ||
document.getElementById("authenticated-view").style.display = "block"; | ||
document.getElementById("unauthenticated-view").style.display = "none"; | ||
} else { | ||
document.getElementById("authenticated-view").style.display = "none"; | ||
document.getElementById("unauthenticated-view").style.display = "block"; | ||
} | ||
})(); | ||
|
||
document.querySelector('#app').innerHTML = ` | ||
<div> | ||
<div id="authenticated-view" style="display: none"> | ||
<button id="logout">Log Out</button> | ||
</div> | ||
<div id="unauthenticated-view" style="display: none"> | ||
<button id="login">Log In</button> | ||
</div> | ||
</div> | ||
`; | ||
|
||
document.getElementById("login").addEventListener("click", async () => { | ||
auth.signIn(); | ||
}); | ||
|
||
document.getElementById("logout").addEventListener("click", async () => { | ||
auth.signOut(); | ||
}); | ||
|
||
``` | ||
|
||
Let’s look into the underlying details of what’s happening here. | ||
|
||
The `auth.initialize` holds the configuration necessary for connecting the app to {{product_name}}. It includes properties like `signInRedirectURL` and `signOutRedirectURL`, which determine where users are redirected after signing in or out. The `clientID` identifies the application, and `baseUrl` specifies the Asgardeo API endpoint specific to your organization. The scope array lists the OAuth 2.0 permissions the app requires, such as `openid` and `profile`. | ||
|
||
The application uses the auth Asgardeo SPA Client instance to access the authentication state and methods (`signIn` and `signOut`). Inside the index.html, the app conditionally renders a login or logout button based on whether the user is authenticated. If the user is authenticated, a "Logout" button is shown that triggers the signOut function. Otherwise, a "Login" button appears, which initiates the signIn process. | ||
|
||
Save the changes and re-run the application in development mode if it is not running already. | ||
|
||
```bash | ||
npm run dev | ||
``` | ||
|
||
Once the application is started, you will see the homepage of the application with the changes we made. | ||
|
||
![Login screen]({{base_path}}/complete-guides/javascript/assets/img/image14.png){: width="800" style="display: block; margin: 0;"} | ||
|
||
Clicking on the login button will initiate an OIDC request. You will be able to observe the authorize request in the browser devtools as follows. To see this, right click on the application and click inspect and switch to the network tab. In the filter input, type “authorize”, and click on the sign in button. | ||
|
||
![OIDC request]({{base_path}}/complete-guides/javascript/assets/img/image15.png){: width="800" style="display: block; margin: 0;"} | ||
|
||
!!! tip "Tip" | ||
|
||
The OpenID Connect specification offers several functions, known as grant types, to obtain an access token in exchange for user credentials. This example uses the authorization code grant type. In this process, the app first requests a unique code from the authentication server, which can later be used to obtain an access token. For more details on the authorization code grant type, please refer to the [Asgardeo documentation.](https://wso2.com/asgardeo/docs/guides/authentication/oidc/implement-auth-code-with-pkce/){:target="_blank"} | ||
|
||
Asgardeo will receive this authorization request and respond by redirecting the user to a login page to enter their credentials. | ||
|
||
|
||
At this stage, **you need to create a [test user in Asgardeo](https://wso2.com/asgardeo/docs/guides/users/manage-users/#onboard-users){:target="_blank"} to try out the application.** Once you create a test user, you can enter the username and password of the test user to the login screen. | ||
|
||
If the login is successful, you should be able to see the application as shown below. | ||
|
||
![Login flow]({{base_path}}/complete-guides/javascript/assets/img/image17.png){: width="800" style="display: block; margin: 0;"} | ||
|
||
!!! tip "Tip" | ||
|
||
**PKCE (Proof Key for Code Exchange)** is an addition to the OAuth2 specification to make the authorization code more immune to replay attacks. It is enabled by default for public clients such as our single page JavaScript application. | ||
|
||
If you want to disable PKCE for some reason, you can do so via following the steps below. **However, disabling PKCE for public clients such as our single page JavaScript app is highly discouraged.** | ||
|
||
1. Log in to the {{product_name}} console and select the application you created. | ||
2. Switch to the Protocol tab. | ||
3. Uncheck the Mandatory checkbox under PKCE section. | ||
|
||
In this section, we have added login and logout features to our JavaScript app. In the next step, we will look into how to access the user attributes of the logged in user. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
--- | ||
template: templates/complete-guide.html | ||
heading: Create a JavaScript app | ||
read_time: 2 min | ||
--- | ||
|
||
For this guide, you will be creating a simple JavaScript app using [Vite](https://vitejs.dev/){:target="_blank"}, a modern, fast and lightweight tool that helps you quickly set up and develop modern JavaScript apps. | ||
|
||
Open a terminal, change directory to where you want to initialize the project, and run the following command to create your first JavaScript sample app. | ||
|
||
|
||
```bash | ||
npm create vite@latest asgardeo-javascript -- --template vanilla | ||
``` | ||
|
||
Running this command will create a folder with a ready-to-run boilerplate JavaScript project, with a development server to run the project and instantly reload changes to the project in your browser without manual refresh. | ||
|
||
Once the application is created, install the dependencies using the following command. | ||
|
||
```bash | ||
cd asgardeo-javascript | ||
npm install | ||
``` | ||
|
||
Then run the sample in the development mode. This allows you to see real-time updates and debug the app as you make changes. | ||
|
||
```bash | ||
npm run dev | ||
``` | ||
|
||
Confirm that the dev server is up and running by verifying the output in the terminal. Then, navigate to [http://localhost:5173](http://localhost:5173){:target="_blank"} and you should see the sample app working in the browser. | ||
|
||
![Navigate to localhost]({{base_path}}/complete-guides/javascript/assets/img/image6.png){: width="800" style="display: block; margin: 0;"} | ||
|
||
At this point, you have a simple yet fully functional JavaScript app. In the next step, let’s try to integrate an Asgardeo JavaScript SDK with the app. |
114 changes: 114 additions & 0 deletions
114
en/asgardeo/docs/complete-guides/javascript/display-logged-in-user-details.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
--- | ||
template: templates/complete-guide.html | ||
heading: Display logged-in user details | ||
read_time: 2 min | ||
--- | ||
|
||
At this point, we’ve successfully implemented login and logout capabilities using the Asgardeo Javascript SDK. The next step is to explore how to access and display logged-in user details within the app. The Asgardeo Javascript SDK loads the basic user attribute details, so that you can directly access those from a variable(such as `user.username`) and use them in the application. | ||
|
||
There may be instances where you’d need to retrieve user attributes outside Javascript components. Asgardeo Javascript SDK provides a [getBasicUserInfo](https://github.com/asgardeo/asgardeo-auth-spa-sdk?tab=readme-ov-file#getbasicuserinfo){:target="_blank"} method, which allows you to retrieve the authenticated user’s basic information. The code example in the following section demonstrates this process and can be adapted to fit your application with any necessary customizations. | ||
|
||
Replace the existing code of `main.js` file with the following given code. Alternatively, you can add highlighted two lines into your existing code of `main.js` file. | ||
|
||
```javascript title="src/main.js" hl_lines="26 36" | ||
|
||
import { AsgardeoSPAClient, SPAUtils } from "@asgardeo/auth-spa"; | ||
|
||
const auth = AsgardeoSPAClient.getInstance(); | ||
|
||
await auth.initialize({ | ||
signInRedirectURL: "http://localhost:5173", | ||
signOutRedirectURL: "http://localhost:5173", | ||
clientID: "<your-app-client-id>", | ||
baseUrl: "https://api.asgardeo.io/t/sagaraorg", | ||
scope: ["openid", "profile"] | ||
}); | ||
|
||
(async () => { | ||
let user = undefined; | ||
|
||
if (SPAUtils.hasAuthSearchParamsInURL()) { | ||
user = await auth.signIn({ callOnlyOnRedirect: true }); | ||
} else { | ||
user = await auth.trySignInSilently(); | ||
} | ||
|
||
if (user) { | ||
document.getElementById("authenticated-view").style.display = "block"; | ||
document.getElementById("unauthenticated-view").style.display = "none"; | ||
document.getElementById("username").innerHTML = "Welcome " + user.username; | ||
} else { | ||
document.getElementById("authenticated-view").style.display = "none"; | ||
document.getElementById("unauthenticated-view").style.display = "block"; | ||
} | ||
})(); | ||
|
||
document.querySelector('#app').innerHTML = ` | ||
<div> | ||
<div id="authenticated-view" style="display: none"> | ||
<p id="username"></p> | ||
<button id="logout">Log Out</button> | ||
</div> | ||
<div id="unauthenticated-view" style="display: none"> | ||
<button id="login">Log In</button> | ||
</div> | ||
</div> | ||
`; | ||
|
||
document.getElementById("login").addEventListener("click", async () => { | ||
auth.signIn(); | ||
}); | ||
|
||
document.getElementById("logout").addEventListener("click", async () => { | ||
auth.signOut(); | ||
}); | ||
|
||
|
||
``` | ||
In the above code snippet, the app utilizes the app instance to access authentication state and methods such as `getBasicUserInfo`, `signIn`, and `signOut`. If the user is authenticated, the app displays a welcome message with the username and a button to log out. If the user is not authenticated, it shows a login button that triggers the sign-in process, and the errors during user info retrieval are handled by logging them to the console. | ||
|
||
If your JavaScript app is already running in the development mode, the home page will be reloaded and you will see the updated user interface. | ||
|
||
![Logout screen]({{base_path}}/complete-guides/javascript/assets/img/image18.png){: width="800" style="display: block; margin: 0;"} | ||
|
||
|
||
Similarly, you can access the other user attributes, such as email, display name, allowed scopes, etc as well. The following code snippet shows you how you can access them in your app. Asgardeo Javascript SDK is responsible for processing the ID token and decoding these attributes. | ||
|
||
```javascript | ||
document.getElementById("scope").innerHTML = user.allowedScopes; | ||
document.getElementById("session").innerHTML = user.sessionState; | ||
document.getElementById("orgName").innerHTML = user.orgName; | ||
|
||
``` | ||
|
||
## Getting additional user attributes | ||
|
||
Other than the above attributes decoded and available to you by default, Asgardeo Javascript SDK provides [getDecodedIDToken](https://github.com/asgardeo/asgardeo-auth-spa-sdk?tab=readme-ov-file#getdecodedidtoken){:target="_blank"} method to access any other user attributes that are not exposed by `getBasicUserInfo`. This method will decode the ID token in browser storage and return the output as a JSON object. | ||
|
||
To get additional user attributes to the ID token, the application should be configured to request the specific user attributes at the time of login. For example, if you want to retrieve a user's mobile number as an attribute, you need to configure the application to request the user’s mobile number as an attribute in the ID token. | ||
|
||
1. Log in to the {{product_name}} console and select the application you created. | ||
2. Go to the **User Attributes** tab. | ||
3. Select the **phone** scope. | ||
4. Expand the scope, and you will see that all attributes under this scope (e.g., `mobile_number`) are selected. | ||
5. Click Update to save the changes. | ||
|
||
```javascript | ||
|
||
auth.getDecodedIDToken().then((idToken) => { | ||
var decodedIdToken = idToken; | ||
console.log(decodedIdToken); | ||
|
||
// Get claims from the decoded idtoken | ||
var phone = decodedIdToken.phone_number; | ||
console.log(phone); | ||
}); | ||
|
||
|
||
``` | ||
|
||
In the above code snippet, we run the `getDecodedIDToken` method if the user is authenticated, and print the output to the browser console. The decoded ID token response will be printed to the browser console as follows. | ||
|
||
![ID token]({{base_path}}/complete-guides/javascript/assets/img/image19.png){: width="800" style="display: block; margin: 0;"} | ||
|
||
In this step, we further improved our JavaScript app to display the user attributes. As the next step, we will try to secure routes within the app. |
Oops, something went wrong.