Skip to content

Exemplos de Implementação

Esta seção contém exemplos práticos de implementação do fluxo de autenticação OAuth 2.0 em diferentes linguagens e frameworks.

C# (ASP.NET Core)

A linguagem nativa do Fanbase. Exemplos com ASP.NET Core e bibliotecas .NET padrão.

Fluxo de Autorização com ASP.NET Core

csharp
// Program.cs ou Startup.cs - Configure serviços
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession();

// Controllers/OAuthController.cs
using Microsoft.AspNetCore.Mvc;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text.Json;

public class OAuthController : Controller
{
    private const string ClientId = "seu_client_id";
    private const string ClientSecret = "seu_client_secret";
    private const string RedirectUri = "https://seu-dominio.com.br/callback";
    private const string LoginBaseUrl = "{login-producao}";
    private const string SecurityBaseUrl = "{security-producao}";

    [HttpGet("/login")]
    public IActionResult IniciarLogin()
    {
        var state = Convert.ToBase64String(RandomNumberGenerator.GetBytes(16)).TrimEnd('=')[..16];
        HttpContext.Session.SetString("oauth_state", state);

        var authUrl = $"{LoginBaseUrl}/authorize?response_type=code&scope=openid%20profile" +
            $"&client_id={ClientId}&redirect_uri={Uri.EscapeDataString(RedirectUri)}&state={state}";

        return Redirect(authUrl);
    }

    [HttpGet("/callback")]
    public async Task<IActionResult> Callback(string? code, string? error, string? state)
    {
        if (!string.IsNullOrEmpty(error))
            return BadRequest($"Erro: {error}");

        var storedState = HttpContext.Session.GetString("oauth_state");
        if (state != storedState)
            return BadRequest("State inválido");

        if (string.IsNullOrEmpty(code))
            return BadRequest("Código não recebido");

        using var http = new HttpClient();
        var content = new FormUrlEncodedContent(new Dictionary<string, string>
        {
            ["grant_type"] = "authorization_code",
            ["client_id"] = ClientId,
            ["client_secret"] = ClientSecret,
            ["code"] = code
        });

        var response = await http.PostAsync($"{SecurityBaseUrl}/api/token/v2", content);
        response.EnsureSuccessStatusCode();

        var json = await response.Content.ReadAsStringAsync();
        var tokens = JsonSerializer.Deserialize<JsonElement>(json);

        var idToken = tokens.GetProperty("id_token").GetString()!;
        var accessToken = tokens.GetProperty("access_token").GetString()!;

        // Valida o id_token (use Microsoft.IdentityModel.Tokens ou System.IdentityModel.Tokens.Jwt)
        // var principal = ValidarIdToken(idToken, ClientId, ClientSecret);

        HttpContext.Session.SetString("access_token", accessToken);
        return Redirect("/dashboard");
    }

    [HttpGet("/userinfo")]
    public async Task<IActionResult> UserInfo()
    {
        var accessToken = HttpContext.Session.GetString("access_token");
        if (string.IsNullOrEmpty(accessToken))
            return Unauthorized();

        using var http = new HttpClient();
        http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
        var response = await http.GetAsync($"{SecurityBaseUrl}/api/userinfo");
        response.EnsureSuccessStatusCode();

        var userInfo = await response.Content.ReadAsStringAsync();
        return Content(userInfo, "application/json");
    }
}

Obter Token com Client Credentials (C#)

csharp
using System.Net.Http.Headers;
using System.Text.Json;

public async Task<string> ObterTokenClientCredentialsAsync()
{
    var clientId = "seu_client_id";
    var clientSecret = "seu_client_secret";
    var securityBaseUrl = "{security-producao}";

    using var http = new HttpClient();
    var content = new FormUrlEncodedContent(new Dictionary<string, string>
    {
        ["grant_type"] = "client_credentials",
        ["client_id"] = clientId,
        ["client_secret"] = clientSecret
    });

    var response = await http.PostAsync($"{securityBaseUrl}/api/token", content);
    response.EnsureSuccessStatusCode();

    var json = await response.Content.ReadAsStringAsync();
    var tokenResponse = JsonSerializer.Deserialize<JsonElement>(json);
    return tokenResponse.GetProperty("access_token").GetString()!;
}

Validação do ID Token em C#

csharp
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;

public ClaimsPrincipal ValidarIdToken(string idToken, string clientId, string clientSecret)
{
    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(clientSecret));
    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

    var validationParameters = new TokenValidationParameters
    {
        ValidIssuer = "fanbase",
        ValidAudience = clientId,
        IssuerSigningKey = key,
        ValidateLifetime = true,
        ClockSkew = TimeSpan.Zero
    };

    var handler = new JwtSecurityTokenHandler();
    var principal = handler.ValidateToken(idToken, validationParameters, out _);
    return principal;
}

Biblioteca Recomendada para JWT em C#

  • Microsoft.IdentityModel.Tokens + System.IdentityModel.Tokens.Jwt (pacotes NuGet padrão)
bash
dotnet add package Microsoft.IdentityModel.Tokens
dotnet add package System.IdentityModel.Tokens.Jwt

JavaScript (Frontend)

Exemplo Completo

javascript
const CLIENT_ID = 'seu_client_id';
const REDIRECT_URI = 'https://seu-dominio.com.br/callback';
const LOGIN_BASE_URL = '{login-producao}';
const SECURITY_BASE_URL = '{security-producao}';

function gerarState() {
  return btoa(Math.random().toString()).substring(0, 16);
}

function iniciarLogin() {
  const state = gerarState();
  sessionStorage.setItem('oauth_state', state);
  
  const authUrl = `${LOGIN_BASE_URL}/authorize?response_type=code&scope=openid profile&client_id=${CLIENT_ID}&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&state=${state}`;
  
  window.location.href = authUrl;
}

async function trocarCodigoPorToken(code) {
  const response = await fetch(`${SECURITY_BASE_URL}/api/token/v2`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      client_id: CLIENT_ID,
      client_secret: 'seu_client_secret',
      code: code
    })
  });

  if (!response.ok) {
    throw new Error('Erro ao trocar código por tokens');
  }

  return await response.json();
}

function processarCallback() {
  const urlParams = new URLSearchParams(window.location.search);
  const code = urlParams.get('code');
  const error = urlParams.get('error');
  const state = urlParams.get('state');
  const storedState = sessionStorage.getItem('oauth_state');

  if (error) {
    console.error('Erro na autenticação:', error);
    return;
  }

  if (state !== storedState) {
    console.error('State não corresponde');
    return;
  }

  if (code) {
    trocarCodigoPorToken(code)
      .then(tokens => {
        console.log('Tokens recebidos:', tokens);
        validarEUsarTokens(tokens);
      })
      .catch(error => {
        console.error('Erro:', error);
      });
  }
}

Node.js (Backend)

Exemplo com Express

javascript
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();

const CLIENT_ID = 'seu_client_id';
const CLIENT_SECRET = 'seu_client_secret';
const REDIRECT_URI = 'https://seu-dominio.com.br/callback';
const LOGIN_BASE_URL = '{login-producao}';
const SECURITY_BASE_URL = '{security-producao}';

app.get('/login', (req, res) => {
  const state = require('crypto').randomBytes(16).toString('hex');
  req.session.oauthState = state;
  
  const authUrl = `${LOGIN_BASE_URL}/authorize?response_type=code&scope=openid profile&client_id=${CLIENT_ID}&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&state=${state}`;
  
  res.redirect(authUrl);
});

app.get('/callback', async (req, res) => {
  const { code, error, state } = req.query;

  if (error) {
    return res.status(400).send(`Erro: ${error}`);
  }

  if (state !== req.session.oauthState) {
    return res.status(400).send('State inválido');
  }

  try {
    const tokenResponse = await fetch(`${SECURITY_BASE_URL}/api/token/v2`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: new URLSearchParams({
        grant_type: 'authorization_code',
        client_id: CLIENT_ID,
        client_secret: CLIENT_SECRET,
        code: code
      })
    });

    const tokens = await tokenResponse.json();

    const decoded = jwt.verify(tokens.id_token, CLIENT_SECRET, {
      issuer: 'fanbase',
      audience: CLIENT_ID
    });

    req.session.user = decoded;
    res.redirect('/dashboard');
  } catch (error) {
    res.status(500).send(`Erro: ${error.message}`);
  }
});

app.get('/userinfo', async (req, res) => {
  const accessToken = req.session.tokens?.access_token;
  
  if (!accessToken) {
    return res.status(401).send('Não autenticado');
  }

  try {
    const response = await fetch(`${SECURITY_BASE_URL}/api/userinfo`, {
      headers: {
        'Authorization': `Bearer ${accessToken}`
      }
    });

    const userInfo = await response.json();
    res.json(userInfo);
  } catch (error) {
    res.status(500).send(`Erro: ${error.message}`);
  }
});

Python

Exemplo com Flask

python
from flask import Flask, redirect, request, session
import requests
import jwt
import secrets

app = Flask(__name__)
app.secret_key = 'sua_chave_secreta'

CLIENT_ID = 'seu_client_id'
CLIENT_SECRET = 'seu_client_secret'
REDIRECT_URI = 'https://seu-dominio.com.br/callback'
LOGIN_BASE_URL = '{login-producao}'
SECURITY_BASE_URL = '{security-producao}'

@app.route('/login')
def login():
    state = secrets.token_urlsafe(16)
    session['oauth_state'] = state
    
    auth_url = f'{LOGIN_BASE_URL}/authorize?response_type=code&scope=openid profile&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&state={state}'
    
    return redirect(auth_url)

@app.route('/callback')
def callback():
    code = request.args.get('code')
    error = request.args.get('error')
    state = request.args.get('state')
    
    if error:
        return f'Erro: {error}', 400
    
    if state != session.get('oauth_state'):
        return 'State inválido', 400
    
    token_data = {
        'grant_type': 'authorization_code',
        'client_id': CLIENT_ID,
        'client_secret': CLIENT_SECRET,
        'code': code
    }
    
    response = requests.post(
        f'{SECURITY_BASE_URL}/api/token/v2',
        data=token_data
    )
    
    tokens = response.json()
    
    try:
        decoded = jwt.decode(
            tokens['id_token'],
            CLIENT_SECRET,
            issuer='fanbase',
            audience=CLIENT_ID,
            algorithms=['HS256']
        )
        session['user'] = decoded
        session['tokens'] = tokens
        return redirect('/dashboard')
    except jwt.InvalidTokenError as e:
        return f'Token inválido: {e}', 400

@app.route('/userinfo')
def userinfo():
    access_token = session.get('tokens', {}).get('access_token')
    
    if not access_token:
        return 'Não autenticado', 401
    
    headers = {'Authorization': f'Bearer {access_token}'}
    response = requests.get(f'{SECURITY_BASE_URL}/api/userinfo', headers=headers)
    
    return response.json()

PHP

Exemplo Básico

php
<?php
session_start();

define('CLIENT_ID', 'seu_client_id');
define('CLIENT_SECRET', 'seu_client_secret');
define('REDIRECT_URI', 'https://seu-dominio.com.br/callback');
define('LOGIN_BASE_URL', '{login-producao}');
define('SECURITY_BASE_URL', '{security-producao}');

function iniciarLogin() {
    $state = bin2hex(random_bytes(16));
    $_SESSION['oauth_state'] = $state;
    
    $authUrl = LOGIN_BASE_URL . '/authorize?' . http_build_query([
        'response_type' => 'code',
        'scope' => 'openid profile',
        'client_id' => CLIENT_ID,
        'redirect_uri' => REDIRECT_URI,
        'state' => $state
    ]);
    
    header('Location: ' . $authUrl);
    exit;
}

function processarCallback() {
    $code = $_GET['code'] ?? null;
    $error = $_GET['error'] ?? null;
    $state = $_GET['state'] ?? null;
    
    if ($error) {
        die('Erro: ' . $error);
    }
    
    if ($state !== $_SESSION['oauth_state']) {
        die('State inválido');
    }
    
    $ch = curl_init(SECURITY_BASE_URL . '/api/token/v2');
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
        'grant_type' => 'authorization_code',
        'client_id' => CLIENT_ID,
        'client_secret' => CLIENT_SECRET,
        'code' => $code
    ]));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    
    $response = curl_exec($ch);
    $tokens = json_decode($response, true);
    
    $_SESSION['tokens'] = $tokens;
    
    return $tokens;
}

function obterUserInfo($accessToken) {
    $ch = curl_init(SECURITY_BASE_URL . '/api/userinfo');
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $accessToken
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    
    $response = curl_exec($ch);
    return json_decode($response, true);
}
?>

Obter Token com Client Credentials (Para Integrações Connect)

JavaScript

javascript
async function obterTokenClientCredentials() {
  const CLIENT_ID = 'seu_client_id';
  const CLIENT_SECRET = 'seu_client_secret';
  const SECURITY_BASE_URL = '{security-producao}';

  const params = new URLSearchParams({
    grant_type: 'client_credentials',
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET
  });

  const response = await fetch(`${SECURITY_BASE_URL}/api/token?${params}`, {
    method: 'POST'
  });

  if (!response.ok) {
    throw new Error('Erro ao obter token');
  }

  const data = await response.json();
  return data.access_token;
}

Node.js

javascript
async function obterTokenConnect() {
  const CLIENT_ID = 'seu_client_id';
  const CLIENT_SECRET = 'seu_client_secret';
  const SECURITY_BASE_URL = '{security-producao}';

  const params = new URLSearchParams({
    grant_type: 'client_credentials',
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET
  });

  const response = await fetch(`${SECURITY_BASE_URL}/api/token?${params}`, {
    method: 'POST'
  });

  const data = await response.json();
  return data.access_token;
}

Usar API Connect

Exemplo: Criar Objeto na Fila (C#)

csharp
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

public async Task<JsonElement> CriarObjetoFilaAsync(string accessToken)
{
    var connectBaseUrl = "{connect-producao}";
    using var http = new HttpClient();

    http.DefaultRequestHeaders.Add("AccessToken", accessToken);
    var body = JsonSerializer.Serialize(new
    {
        action = "ticket-create",
        data = new
        {
            dados_do_ingresso = "valor",
            dados_do_comprador = "valor"
        }
    });

    var content = new StringContent(body, Encoding.UTF8, "application/json");
    var response = await http.PostAsync($"{connectBaseUrl}/api/v1/integration/queue", content);
    response.EnsureSuccessStatusCode();

    var json = await response.Content.ReadAsStringAsync();
    return JsonSerializer.Deserialize<JsonElement>(json);
}

Exemplo: Criar Objeto na Fila (JavaScript)

javascript
async function criarObjetoFila(accessToken) {
  const CONNECT_BASE_URL = '{connect-producao}';

  const response = await fetch(`${CONNECT_BASE_URL}/api/v1/integration/queue`, {
    method: 'POST',
    headers: {
      'AccessToken': accessToken,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      action: 'ticket-create',
      data: {
        dados_do_ingresso: 'valor',
        dados_do_comprador: 'valor'
      }
    })
  });

  if (!response.ok) {
    throw new Error('Erro ao criar objeto na fila');
  }

  return await response.json();
}

Exemplo: Obter Profile Completo (C#)

csharp
using System.Net.Http.Headers;
using System.Text.Json;

public async Task<JsonElement> ObterProfileAsync(string clientId, string jwtToken)
{
    var securityBaseUrl = "{security-producao}";
    using var http = new HttpClient();

    http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken);
    var response = await http.GetAsync($"{securityBaseUrl}/api/profile/{clientId}");
    response.EnsureSuccessStatusCode();

    var json = await response.Content.ReadAsStringAsync();
    var resultado = JsonSerializer.Deserialize<JsonElement>(json);
    var codigo = resultado.GetProperty("header").GetProperty("codigo").GetInt32();

    if (codigo != 1)
        throw new InvalidOperationException(resultado.GetProperty("header").GetProperty("msg").GetString());

    return resultado.GetProperty("data");
}

Exemplo: Obter Profile Completo (JavaScript)

javascript
async function obterProfile(clientId, jwtToken) {
  const SECURITY_BASE_URL = '{security-producao}';

  const response = await fetch(`${SECURITY_BASE_URL}/api/profile/${clientId}`, {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${jwtToken}`
    }
  });

  if (!response.ok) {
    throw new Error('Erro ao obter perfil');
  }

  const resultado = await response.json();
  
  if (resultado.header.codigo !== 1) {
    throw new Error(resultado.header.msg);
  }

  return resultado.data;
}

Recursos Adicionais

Documentação da API Fanbase