Skip to main content

Accessing Protected APIs

When building applications with ThunderID, you'll often need to call protected APIs that require authentication. This guide shows you how to make authenticated HTTP requests using the ThunderID React SDK.

Using SDK Built-in HTTP Client

When your application is wrapped with ThunderIDProvider, you can use the useThunderID hook to access the authenticated http module. This module has the following features:

  • Includes the necessary authentication headers (Bearer token)
  • Handles token refresh when tokens expire
  • Provides methods like request() and requestAll() for making API calls
Accessing the HTTP Client

You can access the http client in two ways:

  1. Inside a component: Use the useThunderID hook to get the http instance

    const { http } = useThunderID()
  2. Outside a component (e.g., in utility functions or services): Import http directly

    import { http } from '@thunderid/react'

Basic API Request

The following examples show how to use the ThunderID SDK's http module to call a protected API endpoint.

Using the Hook Inside a Component

src/UserProfile.jsx
import React, { useEffect, useState } from 'react'
import { useThunderID } from '@thunderid/react'

export default function UserProfile() {
const { http, isSignedIn } = useThunderID()
const [userData, setUserData] = useState(null)

useEffect(() => {
if (!isSignedIn) {
return
}

(async () => {
try {
const response = await http.request({
url: 'https://localhost:8090/users/<user_id>',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
method: 'GET',
})

setUserData(response.data)
} catch (error) {
console.error('Error fetching user data:', error)
}
})()
}, [http, isSignedIn])

if (!isSignedIn) {
return <div>Please sign in to view your profile.</div>
}

return (
<div>
<h2>User Profile</h2>
{userData && <pre>{JSON.stringify(userData, null, 2)}</pre>}
</div>
)
}

Using Direct Import Outside a Component

src/services/userService.js
import { http } from '@thunderid/react'

export async function fetchUser(userId) {
try {
const response = await http.request({
url: `https://localhost:8090/users/${userId}`,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
method: 'GET',
})

return response.data
} catch (error) {
console.error('Error fetching user:', error)
throw error
}
}
src/UserProfile.jsx
import React, { useEffect, useState } from 'react'
import { useThunderID } from '@thunderid/react'
import { fetchUser } from './services/userService'

export default function UserProfile() {
const { isSignedIn } = useThunderID()
const [userData, setUserData] = useState(null)

useEffect(() => {
if (!isSignedIn) {
return
}

(async () => {
try {
const data = await fetchUser('<user_id>')
setUserData(data)
} catch (error) {
console.error('Error loading user data:', error)
}
})()
}, [isSignedIn])

if (!isSignedIn) {
return <div>Please sign in to view your profile.</div>
}

return (
<div>
<h2>User Profile</h2>
{userData && <pre>{JSON.stringify(userData, null, 2)}</pre>}
</div>
)
}
API Configuration

Replace <user_id> with the actual user ID you want to fetch. The ThunderID API server runs on https://localhost:8090 by default.

Storage Type Requirement

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.

warning

Note that you don't need to manually specify the Authorization header, as the http function intercepts the request and attaches the access token automatically. The final request config sent by the http function would be:

Parallel API Requests

To send multiple API requests in parallel, use the httpRequestAll function. It triggers parallel network requests and returns responses after all requests are completed.

The following code snippet shows how to send multiple network requests in parallel:

src/UserProfile.jsx
import React, { useEffect, useState } from 'react'
import { useThunderID } from '@thunderid/react'

export default function UserProfile() {
const { http, isSignedIn } = useThunderID()
const [ userData, setUserData ] = useState({
profile: null,
applications: [],
})

useEffect(() => {
if (!isSignedIn) {
return
}

const requests = []

requests.push({
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
method: 'GET',
url: 'https://localhost:8090/users/<user_id>',
})

requests.push({
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
method: 'GET',
url: 'https://localhost:8090/applications',
})

(async () => {
try {
const response = await http.requestAll(requests)

setUserData({
profile: response[0].data,
applications: response[1].data,
})
} catch (error) {
console.error('Error fetching data:', error)
}
})()
}, [http, isSignedIn])

return <pre>{JSON.stringify(userData, null, 4)}</pre>
}

Using a GraphQL Client

If you are not using webWorker as the storage type, use the getAccessToken function to fetch the access token. Then manually attach the token to the GraphQL client's authentication headers.

Storage Type Limitation

This approach is not available when the storage type is set to webWorker. The SDK automatically manages the access token and does not expose it to the main thread.

The following example shows how to configure a GraphQL client with authentication using the access token:

src/graphql/client.js
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'
import { setContext } from '@apollo/client/link/context'

export function createAuthenticatedClient(accessToken) {
const httpLink = createHttpLink({
uri: 'https://localhost:8090/graphql',
})

const authLink = setContext((_, { headers }) => {
return {
headers: {
...headers,
authorization: accessToken ? `Bearer ${accessToken}` : '',
},
}
})

return new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
})
}
src/UserProfile.jsx
import React, { useEffect, useState } from 'react'
import { useThunderID } from '@thunderid/react'
import { gql } from '@apollo/client'
import { createAuthenticatedClient } from './graphql/client'

const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
email
username
firstName
lastName
}
}
`

export default function UserProfile() {
const { isSignedIn, getAccessToken } = useThunderID()
const [userData, setUserData] = useState(null)

useEffect(() => {
if (!isSignedIn) {
return
}

(async () => {
try {
const accessToken = await getAccessToken()
const client = createAuthenticatedClient(accessToken)

const { data } = await client.query({
query: GET_USER,
variables: { id: '<user_id>' },
})

setUserData(data.user)
} catch (error) {
console.error('Error fetching user data:', error)
}
})()
}, [isSignedIn, getAccessToken])

if (!isSignedIn) {
return <div>Please sign in to view your profile.</div>
}

return (
<div>
<h2>User Profile</h2>
{userData && <pre>{JSON.stringify(userData, null, 2)}</pre>}
</div>
)
}
tip

Replace <user_id> with the actual user ID you want to fetch. This example uses Apollo Client, but you can apply the same pattern with other GraphQL clients like urql or graphql-request.

ThunderID LogoThunderID Logo

Product

DocsAPIsSDKs
© WSO2 LLC. All rights reserved.Privacy PolicyCookie Policy