Pular para o conteúdo
Documentação · Qualquer biblioteca OIDC

Guia rápido: qualquer biblioteca OIDC

O Usher é um provedor OpenID Connect padrão. Se a sua linguagem tem um cliente OIDC certificado, você já tem tudo de que precisa: aponte-o para o documento de descoberta do seu ambiente e use o fluxo de código de autorização com PKCE.

As configurações

ConfiguraçãoValor
Emissorhttps://<handle>.usherid.com
URL de descobertahttps://<handle>.usherid.com/.well-known/openid-configuration
FluxoCódigo de autorização (response_type=code)
PKCEObrigatório, code_challenge_method=S256
Escoposopenid profile email offline_access
Autenticação do clienteConforme listado em token_endpoint_auth_methods_supported

O handle do seu ambiente está no Usher Console, ao lado do emissor. Os ambientes de desenvolvimento recebem um aleatório, como wise-otter-42; os de produção têm o handle que você escolheu. Um ambiente de produção também pode ficar no seu próprio domínio, como login.acme.com: nesse caso, esse passa a ser o emissor dele, depois que você apontar o domínio para o Usher com um registro CNAME.

Leia o documento de descoberta

Todos os endpoints e chaves de que o seu cliente precisa estão listados aqui. Deixe a sua biblioteca ler o documento, em vez de copiar URLs para o seu código.

Terminal
curl -s https://acme.usherid.com/.well-known/openid-configuration | jq
Resposta (resumida)
{
  "issuer": "https://acme.usherid.com",
  "authorization_endpoint": "https://acme.usherid.com/api/auth/oauth2/authorize",
  "token_endpoint": "https://acme.usherid.com/api/auth/oauth2/token",
  "userinfo_endpoint": "https://acme.usherid.com/api/auth/oauth2/userinfo",
  "jwks_uri": "https://acme.usherid.com/api/auth/jwks",
  "introspection_endpoint": "https://acme.usherid.com/api/auth/oauth2/introspect",
  "revocation_endpoint": "https://acme.usherid.com/api/auth/oauth2/revoke",
  "end_session_endpoint": "https://acme.usherid.com/api/auth/oauth2/end-session",
  "scopes_supported": ["openid", "profile", "email", "offline_access"],
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token", "client_credentials"],
  "code_challenge_methods_supported": ["S256"]
}

O fluxo

Envie a pessoa ao endpoint de autorização

Gere um verificador PKCE aleatório e guarde-o, com um state aleatório, em um lugar que só a sessão deste navegador alcance (um cookie httpOnly de curta duração funciona bem). Depois, redirecione com response_type=code, o seu client_id e redirect_uri, os escopos acima, o state e o code_challenge S256 do seu verificador.

Deixe a pessoa iniciar sessão

A partir daqui, o Lobby assume: ele mostra o nome do seu app, oferece os métodos de início de sessão que o seu ambiente permite e pede consentimento na primeira vez.

Verifique o callback

O Usher redireciona para a sua redirect_uri com code e state. Recuse a resposta, a menos que o state seja igual ao que você guardou. O código é de uso único e dura cinco minutos.

Troque o código por tokens

A partir do seu servidor, envie o código e o verificador PKCE com um POST para o endpoint de token:

Requisição de token
curl -s -X POST https://acme.usherid.com/api/auth/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d grant_type=authorization_code \
-d code="$CODE" \
-d redirect_uri=https://app.acme.example/callback \
-d code_verifier="$CODE_VERIFIER"

Valide o token de ID

Verifique a assinatura dele com as chaves do jwks_uri e confira se iss é o seu emissor, se aud é o seu ID de cliente e se exp está no futuro. A sua biblioteca faz isso por você; confirme que essa verificação não está desativada.

No Node.js

O openid-client faz tudo isso, inclusive a validação:

openid-client
import * as client from 'openid-client'

// discovery: every endpoint and key comes from the issuer
const config = await client.discovery(
  new URL('https://acme.usherid.com'),
  process.env.USHER_CLIENT_ID!,
  process.env.USHER_CLIENT_SECRET!,
)

// 1. send them to the Lobby, with PKCE (S256) and a state to check later
const codeVerifier = client.randomPKCECodeVerifier()
const state = client.randomState()
const url = client.buildAuthorizationUrl(config, {
  redirect_uri: 'https://app.acme.example/callback',
  scope: 'openid profile email offline_access',
  code_challenge: await client.calculatePKCECodeChallenge(codeVerifier),
  code_challenge_method: 'S256',
  state,
})
// keep codeVerifier and state in a short-lived httpOnly cookie, then redirect to url

// 2. back at /callback: swap the code for tokens
const tokens = await client.authorizationCodeGrant(config, new URL(request.url), {
  pkceCodeVerifier: codeVerifier,
  expectedState: state,
})
const { sub, email, name } = tokens.claims()!

Em outras linguagens

Estas bibliotecas muito usadas falam OpenID Connect padrão e funcionam com o Usher sem nada específico do Usher:

LinguagemBiblioteca
PythonAuthlib
Gocoreos/go-oidc com golang.org/x/oauth2
JavaSpring Security OAuth 2.0 Client
.NETMicrosoft.AspNetCore.Authentication.OpenIdConnect
Rubyomniauth_openid_connect
PHPjumbojett/openid-connect-php

Como manter a sessão iniciada

Com o escopo offline_access, a resposta de token inclui um token de atualização. Use-o com grant_type=refresh_token para obter um novo token de acesso quando o antigo expirar. Os tokens de atualização passam por rotação: cada uso devolve um novo, e o antigo deixa de funcionar.

Como finalizar a sessão

Primeiro, limpe a sua própria sessão; depois, redirecione para o end_session_endpoint com post_logout_redirect_uri (e id_token_hint, se você tiver), para que o Lobby também esqueça a pessoa.