Skip to content

Commit

Permalink
Add oauth docs
Browse files Browse the repository at this point in the history
  • Loading branch information
bcbogdan committed Sep 17, 2024
1 parent 3a668ff commit 9cb4848
Show file tree
Hide file tree
Showing 8 changed files with 689 additions and 0 deletions.
14 changes: 14 additions & 0 deletions v2/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,20 @@ module.exports = {
beforeDefaultRemarkPlugins,
},
],
[
"@docusaurus/plugin-content-docs",
{
id: "oauth",
path: "oauth",
routeBasePath: "docs/oauth",
sidebarPath: require.resolve("./oauth/sidebars.js"),
showLastUpdateTime: true,
editUrl: "https://github.com/supertokens/docs/tree/master/v2/",
remarkPlugins: remarkPlugins,
rehypePlugins: rehypePlugins,
beforeDefaultRemarkPlugins,
},
],
[
"@docusaurus/plugin-content-docs",
{
Expand Down
138 changes: 138 additions & 0 deletions v2/oauth/clients-without-dedicated-backend.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
---
title: Clients without dedicated backends
hide_title: true
---

# Clients Without Dedicated Backends

You can use the following guide if you have frontend clients that use a separate domain for authentication but do not have dedicated backends for other functionalities.

## 1. Set Up Your Authentication Portal

First, initialize and setup **SuperTokens** according to the [quick setup guide](#).

## 2. Initialize the OAuth2Provider

In addition to the authentication recipes you’ve set up, initialize the OAuth2Provider recipe on your backend service.
The default settings should be sufficient for most use cases.

```typescript
import supertokens from "supertokens-node";
import OAuth2Provider from"supertokens-node/recipe/oauth2";

supertokens.init({
framework: "express",
supertokens: {
connectionURI: "<YOUR_CONNECTION_URI>",
apiKey: "<YOUR_API_KEY>",
},
appInfo: {
appName: "",
apiDomain: "<YOUR_API_DOMAIN>",
websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
apiBasePath: "/auth",
websiteBasePath: "/auth"
},
recipeList: [
// This is where you initialize the OAuth2 recipe
// TODO: Show the config parameters here
OAuth2Provider.init(),
]
});
```

## 3. Add a Way to Create OAuth2 Clients

We have to create OAuth2 clients in order to allow them to authenticate through our flow.

First we need to add a method to do this.
Our recommendation is to use the `createClient` function that is exposed by our SDK.
Alternatively, you can also directly call the **SuperTokens** core API.

### Using the `createClient` function

```typescript
import { createClient } from "supertokens-node/recipe/oauth2";

createClient({
// This value will be shown in the auth page when the app requests the user to authenticate
clientName: 'My Application',
// TODO: Add info about this
responseTypes: ['code', 'id_token'],
// TODO: Add info about this
grantTypes: ['authorization_code', 'refresh_token'],
// TODO: Add info about this
redirectUri: 'https://example.com/oauth/callback',
});

```

### Using the Core API

```bash
## TODO: This is a dummy example.
curl -X POST https://api.auth.example.com/oauth2/clients \
-H "Content-Type: application/json" \
-d '{
"client_name": "My Application",
"response_types": ["code", "id_token"],
"grant_types": ["authorization_code", "refresh_token"],
"redirect_uris": ["https://different.com/oauth/callback"]
}'
```

## 4. Create Separate Clients for Each Application

Using the method that we defined in the previous step create separate clients for each of your applications.

Repeat the process for each domain, adjusting the `clientName` and `redirectUri` as necessary.


## 5. Set Up Your Frontend and Integrate with an OIDC Library

Integrate your frontend applications with a generic OAuth2 or OIDC library. Here are a few popular options: [oidc-client-js](https://github.com/IdentityModel/oidc-client-js), [openid-client](https://github.com/panva/node-openid-client)

### Example Using `oidc-client-js`

```html
<!-- index.html -->
<script src="https://cdn.jsdelivr.net/npm/oidc-client@latest/dist/oidc-client.min.js"></script>
<script>
const config = {
authority: 'https://api.auth.example.com',
client_id: 'YOUR_CLIENT_ID',
redirect_uri: 'https://yourdomain.com/oauth/callback',
response_type: 'code',
scope: 'openid profile email',
post_logout_redirect_uri: 'https://yourdomain.com/logout',
};
const userManager = new Oidc.UserManager(config);
// Handle login redirection
function login() {
userManager.signinRedirect();
}
// Handle logout redirection
function logout() {
userManager.signoutRedirect();
}
// Handle user session
userManager.getUser().then(function (user) {
if (user) {
document.getElementById('user-info').innerText = `Hello, ${user.profile.name}`;
}
});
// Setup login button
document.getElementById('login-button').addEventListener('click', login);
document.getElementById('logout-button').addEventListener('click', logout);
</script>

<button id="login-button">Login with OAuth2</button>
<button id="logout-button">Logout</button>
<div id="user-info"></div>
```

74 changes: 74 additions & 0 deletions v2/oauth/introduction.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
title: Introduction
hide_title: true
---

# OAuth2 Support

**OAuth2**, Open Authorization, is an industry-standard authorization framework that enables third-party applications to obtain limited access to a user's resources without exposing their credentials.
It is commonly used for single sign-on (SSO) and authorization.

## When to use OAuth2

In most cases, when using **SuperTokens**, you should not have to use OAuth2 directly.
We already expose the `ThirdParty` recipe that enables users to login using external providers.
This covers most of the authentication scenarios that involve OAuth2.

However, there are some custom use cases where you will have to implement a different authentication flow.

- **[If you have multiple frontends connecting to the same backend](/docs)**
- **[If you want to have an unified login experience across multiple domains](/docs)**
- **[If you want to reuse your website login for desktop and mobile apps](/docs)**
- **[For Machine to Machine communication](/docs)**

For these specific instances we expose an `OAuth` recipe that allows you to complete your setup.


## OAuth2 Reference

Before we explore our OAuth2 implementation let's first recap some common terms and concepts that are used in the framework.
We will use them throughout the next pages.

### Clients

An OAuth 2.0 client is an application that interacts with an OAuth 2.0 provider to request access to a user's resources.
It then utilizes the access tokens granted by the provider to perform authorized operations on behalf of the user.

The term **client** does not imply any particular implementation characteristics (e.g. whether the application executes on a server, a desktop, or other devices).


### Tokens

An OAuth token is a credential used to access protected resources on behalf of a user.

#### Access Token

Access tokens are what the OAuth client uses to make requests to an API. The access token is meant to be read and validated by the API.

#### ID Token

An ID token contains information about what happened when a user authenticated, and is intended to be read by the OAuth client.
The ID token may also contain information about the user such as their name or email address, although that is not a requirement of an ID token.

#### Refresh Token

An OAuth Refresh Token is a string that the OAuth client can use to get a new access token without the user's interaction.

### Flows

Flows are the set of steps a Client has to perform in order to obtain an access token.
Our implementation supports the following grant types:
- [Authorization Code](https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.1)
- [Implicit](https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.2)
- [Client credentials](https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.4)

### Scopes

Scopes in OAuth 2.0 specify the level of access an application is requesting from the user's resources.
This way you can define the boundaries and permissions for what the access token can do.

### PKCE

PKCE (RFC 7636) is an extension to the Authorization Code flow to prevent CSRF and authorization code injection attacks. https://oauth.net/2/pkce/
We support PKCE and recommend that you use a library that makes use of it.
You can opt-in by setting the code_challenge (and optionally code_challenge_method) parameters in the authorization URL and then verifying it after the user gets redirected back to the client.
127 changes: 127 additions & 0 deletions v2/oauth/machine-to-machine-authentication.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
---
title: Machine to Machine Authentication
hide_title: true
---

# Machine to Machine Authentication

You can use the following guide if you want to implement a custom authentication flow between your microservices.

## 1. Set Up Your Authentication Portal

First, initialize and setup **SuperTokens** according to the [quick setup guide](#).

## 2. Initialize the OAuth2Provider

In addition to the authentication recipes you’ve set up, initialize the OAuth2Provider recipe on your backend service.
The default settings should be sufficient for most use cases.

```typescript
import supertokens from "supertokens-node";
import OAuth2Provider from"supertokens-node/recipe/oauth2";

supertokens.init({
framework: "express",
supertokens: {
connectionURI: "<YOUR_CONNECTION_URI>",
apiKey: "<YOUR_API_KEY>",
},
appInfo: {
appName: "",
apiDomain: "<YOUR_API_DOMAIN>",
websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
apiBasePath: "/auth",
websiteBasePath: "/auth"
},
recipeList: [
// This is where you initialize the OAuth2 recipe
// TODO: Show the config parameters here
OAuth2Provider.init(),
]
});
```

## 3. Add a Way to Create OAuth2 Clients

We have to create OAuth2 clients in order to allow them to authenticate through our flow.

First we need to add a method to do this.
Our recommendation is to use the `createClient` function that is exposed by our SDK.
Alternatively, you can also directly call the **SuperTokens** core API.

### Using the `createClient` function

```typescript
import { createClient } from "supertokens-node/recipe/oauth2";

createClient({
// This value will be shown in the auth page when the app requests the user to authenticate
clientName: 'My Application',
// TODO: Add info about this
responseTypes: ['code', 'id_token'],
// TODO: Add info about this
grantTypes: ['client_credentials'],
});

```

### Using the Core API

```bash
## TODO: This is a dummy example.
curl -X POST https://api.auth.example.com/oauth2/clients \
-H "Content-Type: application/json" \
-d '{
"client_name": "My Application",
"response_types": ["code", "id_token"],
"grant_types": ["client_credentials"]
}'
```

## 4. Create Separate Clients for Each Application

Using the method that we defined in the previous step create separate clients for each of your applications/microservices.

Repeat the process for each domain, adjusting the `clientName`.

## 5. How to Create Tokens

To generate tokens for your microservices using the `client_credentials` grant type, use the following code snippet:

```typescript
const generateToken = async (client, scope) => {
try {
const res = await fetch('https://api.auth.example.com/auth/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
client_id: client.clientId,
client_secret: client.clientSecret,
grant_type: 'client_credentials',
scope,
}),
});

const tokenData = await res.json();
if (!res.ok) {
throw new Error(`Error fetching token: ${tokenData.error_description}`);
}

console.log('Token created successfully:', tokenData);
} catch (error) {
console.error('Error creating token:', error);
}
};

// Example usage
const client = {
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET',
};

generateToken(client, 'your-desired-scope');
```


Loading

0 comments on commit 9cb4848

Please sign in to comment.