Skip to content

Commit

Permalink
Update documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
ghostzero committed Nov 25, 2024
1 parent a1b79ed commit 88ff278
Show file tree
Hide file tree
Showing 3 changed files with 217 additions and 23 deletions.
218 changes: 206 additions & 12 deletions docs/docs/authorization.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,20 @@ We currently support two types of tokens:

User Access Tokens and App Access Tokens are both bearer tokens. Bearer tokens are used to authenticate the application.

## Authorization Code Flow
## Issuing Access Tokens

### Authorization Code Flow Overview
### Requesting Tokens

1. The client sends a request to the authorization server asking for an authorization code.
2. The authorization server authenticates the client and issues an authorization code.
3. The client redirects the user back to the application with the authorization code.
4. The application exchanges the authorization code for an access token.
Using OAuth2 via the authorization code flow is how most developers are familiar with OAuth2.
When using the authorization code flow, the client will redirect the user to the authorization server to grant access to
the application. The authorization server will then redirect the user back to the application with an authorization code
in the URL. The client will then exchange the authorization code for an access token.

### Authorization Code Flow Example
Later, the client can use the access token to access the user's data.

In the following example, we will use the authorization code flow to get an access token.
#### Redirecting for Authorization

Once a client has been created, we will use the authorization code flow to get an access token.
To visualize the flow, we will use javascript to redirect the user to the authorization server. You will find your
client id in the [Passport Client](https://console.dev.own3d.tv/resources/passport-clients) section of the OWN3D
Developer Console.
Expand All @@ -67,20 +69,38 @@ Otherwise, the authorization server will throw a "**Client authentication failed
window.location.href = "https://id.stream.tv/oauth/authorize?client_id=<>&redirect_uri=<>&response_type=code&scope=<>";
```

The `prompt` parameter can be used to specify the authentication behavior. The following values are supported:

- `none`: OWN3D ID will always throw an authentication error if the user is not already authenticated.
- `consent`: OWN3D ID always display the authorization approval screen, even if all scopes are already granted.
- `login`: OWN3D ID will always prompt the user to re-login, even if they are already logged in.

If no `prompt` value is provided, the user will be prompted for authorization only if they have not previously
authorized access to the consuming application for the requested scopes.

The `login-fallback` parameter can be used to specify the fallback behavior if the user is not logged in depending on
the `prompt` value. The following values are supported: `twitch`, `youtube`, `tiktok` and other providers.

#### Approving the Request

The user will then be redirected to the application with the authorization code in the URL. From there, the user must
click on the "Authorize" button to grant the application access to the user's data:

<div style="text-align: center">
<img src="../images/oauth-authorization.png" alt="Authorization Code Flow" style="border: 1px solid #181e23; border-radius: 8px;"/>
</div>

#### Converting Authorization Codes to Access Tokens

After that we use php to get the access token from the authorization server.

```php
use Illuminate\Support\Facades\Http;

// Get the authorization code from the URL
$code = $_GET['code'];
// Exchange the authorization code for an access token using laravel http facades
$response = \Http::post('https://id.stream.tv/oauth/token', [
$response = Http::post('https://id.stream.tv/oauth/token', [
'client_id' => '<>',
'client_secret' => '<>',
'redirect_uri' => '<>',
Expand All @@ -94,7 +114,17 @@ $access_token = $response->json()['access_token'];
If you are familiar with laravel, you may want to check our [own3d/id](https://github.com/own3d/id) package.
It is a laravel package that provides a simple way to work with our API's.

## Refresh Tokens
### Requesting All Scopes

If you want to request all scopes, you can use the `*` wildcard.

```javascript
// Redirect the user to the authorization server

window.location.href = "https://id.stream.tv/oauth/authorize?client_id=<>&redirect_uri=<>&response_type=code&scope=*";
```

### Refresh Tokens

Refresh tokens are used to obtain a new access token when the current one expires.
With the following example, we will use the refresh token flow to get a new access token.
Expand All @@ -114,7 +144,7 @@ $response = \Http::post('https://id.stream.tv/oauth/token', [
$access_token = $response->json()['access_token'];
```

## Token Expiration
### Token Expiration

Typically, the `/oauth/token` endpoint will return a `expires_in` field that indicates the number of seconds until the
token expires.
Expand All @@ -126,7 +156,145 @@ If you don't use the refresh token within 30 days, the user will be required to

Personal access tokens having a lifetime of 6 months. These tokens cannot be refreshed automatically.

## Scopes
## Authorization Code Grant With PKCE

The authorization code grant with "Proof Key for Code Exchange" (PKCE) is an extension of the authorization code grant
that is intended to be more secure for public clients.

### Creating the Client

Before your application can issue tokens via the authorization code grant with PKCE, you will need to create a
PKCE-enabled client. A PKCE-enabled client is a client that does not have a client secret.

### Requesting Tokens

#### Code Verifier and Code Challenge

As this authorization grant does not provide a client secret, developers will need to generate a combination of a code
verifier and a code challenge in order to request a token.

The code verifier should be a random string of between 43 and 128 characters containing letters, numbers,
and `-`, `.`, `_`, `~` characters, as defined in the [RFC 7636 specification](https://tools.ietf.org/html/rfc7636).

The code challenge should be a Base64 encoded string with URL and filename-safe characters. The trailing `=` characters
should be removed and no line breaks, whitespace, or other additional characters should be present.

```php
$encoded = base64_encode(hash('sha256', $code_verifier, true));

$codeChallenge = strtr(rtrim($encoded, '='), '+/', '-_');
```

or in javascript:

```typescript
function dec2hex(dec) {
return ('0' + dec.toString(16)).substr(-2)
}

function generateRandomString() {
const array = new Uint32Array(56 / 2)
crypto.getRandomValues(array)
return Array.from(array, dec2hex).join('')
}

function sha256(plain) {
const encoder = new TextEncoder()
const data = encoder.encode(plain)
return crypto.subtle.digest('SHA-256', data)
}

function base64urlencode(a) {
let str = ''
const bytes = new Uint8Array(a)
const len = bytes.byteLength
for (let i = 0; i < len; i++) {
str += String.fromCharCode(bytes[i])
}
return btoa(str)
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '')
}

const codeVerifier = generateRandomString()
const codeChallange = base64urlencode(await sha256(codeVerifier))
```

#### Redirecting for Authorization

Once a client has been created, you may use the client ID and the generated code verifier and code challenge to request
an authorization code and access token from your application. First, the consuming application should make a redirect
request to OWN3D ID's `/oauth/authorize` route:

```php
use Illuminate\Http\Request;
use Illuminate\Support\Str;

Route::get('/redirect', function (Request $request) {
$request->session()->put('state', $state = Str::random(40));

$request->session()->put(
'code_verifier', $code_verifier = Str::random(128)
);

$codeChallenge = strtr(rtrim(
base64_encode(hash('sha256', $code_verifier, true))
, '='), '+/', '-_');

$query = http_build_query([
'client_id' => 'client-id',
'redirect_uri' => 'https://third-party-app.com/callback',
'response_type' => 'code',
'scope' => '',
'state' => $state,
'code_challenge' => $codeChallenge,
'code_challenge_method' => 'S256',
// 'prompt' => '', // "none", "consent", or "login"
]);

return redirect('https://id.stream.tv/oauth/authorize?'.$query);
});
```

#### Converting Authorization Codes to Access Tokens

If the user approves the request, the authorization server will redirect the user back to the application with an
authorization code in the URL. The application can then exchange the authorization code for an access token:

```php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

Route::get('/callback', function (Request $request) {
$state = $request->session()->pull('state');

$codeVerifier = $request->session()->pull('code_verifier');

throw_unless(
strlen($state) > 0 && $state === $request->state,
InvalidArgumentException::class
);

$response = Http::asForm()->post('https://id.stream.tv/oauth/token', [
'grant_type' => 'authorization_code',
'client_id' => 'client-id',
'redirect_uri' => 'https://third-party-app.com/callback',
'code_verifier' => $codeVerifier,
'code' => $request->code,
]);

return $response->json();
});
```

## Password Grant Tokens

The password grant is no longer supported and should not be used.
See [here](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#name-resource-owner-password-cre) for
more information.

## Token Scopes

With Scope, you can specify the level of access that the application is requesting.
We currently support the following scopes:
Expand Down Expand Up @@ -160,3 +328,29 @@ We currently support the following scopes:

You will also find all scopes in our [Scope](https://github.com/own3d/id/blob/master/src/Enums/Scope.php) Enum in
GitHub.

## Linking Third-Party Accounts

To link third-party service accounts, you can use the `/oauth/{provider}` endpoint.

The `provider` parameter is the name of the provider you want to link. We currently support the following
providers: `twitch`, `youtube`, `tiktok`, `discord` and `spotify`.

The `continue` parameter is the URL that the user should be redirected to after linking the account.

The `prompt` parameter can be used to specify the authentication behavior. This parameter will be passed to the
third-party service. Not all providers support all values. The following values are supported:

**YouTube**

- `consent`: Always display the authorization approval screen, even if all scopes are already granted.

**TikTok**

- `login`: Always prompt the user to re-login. This will force the user to logout and re-login to TikTok.

## Logging Out

To log out the user, you can use the `/logout` endpoint.

The `continue` parameter is the URL that the user should be redirected to after logging out.
19 changes: 9 additions & 10 deletions docs/docs/cloud/edge-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,23 +50,22 @@ You can use JavaScript modules from npm in your Deno programs with the "**npm:**
![postman client](../../images/Postman_Exh1yNav6L.png)

```js
import jwt from 'npm:jsonwebtoken';
import express from 'npm:express';
import { decode } from 'jsr:@gz/jwt'
import express from 'npm:express'

export const verifyToken = (req, res, next) => {
export const verifyToken = async (req, res, next) => {
const authHeader = req.headers.authorization;

if (authHeader && authHeader.startsWith('Bearer ')) {
const token = authHeader.substring(7, authHeader.length);

jwt.verify(token, 'secret', (err, decoded) => {
if (err) {
return res.status(403).json({ message: 'Invalid token' });
}

req.user = decoded; // Add the decoded token to the request object
try {
// Add the decoded token to the request object
req.user = await decode(token, 'secret', {algorithm: 'HS256'});
next(); // Proceed to the next middleware or route handler
});
} catch (_err) {
return res.status(403).json({ message: 'Invalid token' });
}
} else {
res.status(401).json({ message: 'No token provided' });
}
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
"docs:dev": "set NODE_OPTIONS=\"--openssl-legacy-provider\" && vuepress dev docs",
"docs:build": "set NODE_OPTIONS=\"--openssl-legacy-provider\" && vuepress build docs"
},
"dependencies": {}
"dependencies": {},
"packageManager": "[email protected]+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}

0 comments on commit 88ff278

Please sign in to comment.