Pular para o conteúdo principal

Adicionar autenticação ao seu aplicativo Passport.js

Este guia mostrará como integrar o Logto ao seu aplicativo com Passport.js e estratégia OIDC.

dica
  • Neste guia, assumimos que você configurou o Express com sessão em seu projeto. Se você ainda não fez isso, confira o site do Express.js para começar.

Pré-requisitos

Instalação

Importe o Logto SDK através do seu gerenciador de pacotes favorito:

npm i passport passport-openidconnect

Integração

Inicializar Passport.js com a estratégia OIDC

passport.ts
import passport from 'passport';
import OpenIDConnectStrategy, { type Profile, type VerifyCallback } from 'passport-openidconnect';

const endpoint = '<your-logto-endpoint>';
const appId = '<your-application-id>';
const appSecret = '<your-application-secret>';

export default function initPassport() {
passport.use(
new OpenIDConnectStrategy(
{
issuer: `${endpoint}/oidc`,
authorizationURL: `${endpoint}/oidc/auth`,
tokenURL: `${endpoint}/oidc/token`,
userInfoURL: `${endpoint}/oidc/me`,
clientID: appId,
clientSecret: appSecret,
callbackURL: '/callback',
scope: ['profile', 'offline_access'],
},
(issuer: string, profile: Profile, callback: VerifyCallback) => {
callback(null, profile);
}
)
);

passport.serializeUser((user, callback) => {
callback(null, user);
});

passport.deserializeUser(function (user, callback) {
callback(null, user as Express.User);
});
}

Este código inicializa o Passport com a OpenIDConnectStrategy. Os métodos serialize e deserialize são configurados para fins de demonstração.

Certifique-se de inicializar e anexar o middleware Passport em seu aplicativo:

your-app-entry.ts
import initPassport from './passport';

// ... other code
initPassport();
// ... other code
app.use(passport.authenticate('session'));
// ... other code

Configurar URIs de redirecionamento

Antes de mergulharmos nos detalhes, aqui está uma visão geral rápida da experiência do usuário final. O processo de login pode ser simplificado da seguinte forma:

  1. Seu aplicativo invoca o método de login.
  2. O usuário é redirecionado para a página de login do Logto. Para aplicativos nativos, o navegador do sistema é aberto.
  3. O usuário faz login e é redirecionado de volta para o seu aplicativo (configurado como o URI de redirecionamento).
Sobre o login baseado em redirecionamento
  1. Este processo de autenticação segue o protocolo OpenID Connect (OIDC), e o Logto aplica medidas de segurança rigorosas para proteger o login do usuário.
  2. Se você tiver vários aplicativos, pode usar o mesmo provedor de identidade (Logto). Uma vez que o usuário faz login em um aplicativo, o Logto completará automaticamente o processo de login quando o usuário acessar outro aplicativo.

Para saber mais sobre a lógica e os benefícios do login baseado em redirecionamento, veja Experiência de login do Logto explicada.


nota

Nos trechos de código a seguir, assumimos que seu aplicativo está sendo executado em http://localhost:3000/.

Configurar URIs de redirecionamento

Vá para a página de detalhes do aplicativo no Logto Console. Adicione um URI de redirecionamento http://localhost:3000/callback.

URI de redirecionamento no Logto Console

Assim como no login, os usuários devem ser redirecionados para o Logto para sair da sessão compartilhada. Uma vez concluído, seria ótimo redirecionar o usuário de volta para o seu site. Por exemplo, adicione http://localhost:3000/ como a seção de URI de redirecionamento pós logout.

Em seguida, clique em "Salvar" para salvar as alterações.

Implementar login e logout

Agora vamos criar rotas específicas para os processos de autenticação:

your-app-entry.ts
app.get('/sign-in', passport.authenticate('openidconnect'));
app.get(
'/callback',
passport.authenticate('openidconnect', {
successReturnToOrRedirect: '/',
})
);
app.get('/sign-out', (request, response, next) => {
request.logout((error) => {
if (error) {
next(error);
return;
}
response.redirect(`${endpoint}/oidc/session/end?client_id=${appId}`);
});
});

Em seguida, adicione à página inicial

your-app-entry.ts
app.get('/', (request: Request, response) => {
const { user } = request;
response.setHeader('content-type', 'text/html');

if (user) {
response.end(
`<h1>Hello Logto</h1><p>Signed in as ${JSON.stringify(
user
)}, <a href="/sign-out">Sign Out</a></p>`
);
} else {
response.end(`<h1>Hello Logto</h1><p><a href="/sign-in">Sign In</a></p>`);
}
});

Ponto de verificação: Teste seu aplicativo

Agora, você pode testar seu aplicativo:

  1. Execute seu aplicativo, você verá o botão de login.
  2. Clique no botão de login, o SDK iniciará o processo de login e redirecionará você para a página de login do Logto.
  3. Após fazer login, você será redirecionado de volta para o seu aplicativo e verá o botão de logout.
  4. Clique no botão de logout para limpar o armazenamento local e sair.

Escopos e reivindicações

Logto usa as convenções de escopos e reivindicações do OIDC para definir os escopos e reivindicações para recuperar informações do usuário do Token de ID e do endpoint userinfo do OIDC. Tanto "escopo" quanto "reivindicação" são termos das especificações OAuth 2.0 e OpenID Connect (OIDC).

Em resumo, quando você solicita um escopo, você obterá as reivindicações correspondentes nas informações do usuário. Por exemplo, se você solicitar o escopo `email`, você obterá os dados `email` e `email_verified` do usuário.

Por padrão, o Logto SDK sempre solicitará três escopos: `openid`, `profile` e `offline_access`, e não há como remover esses escopos padrão. Mas você pode adicionar mais escopos ao configurar o Logto:

export default function initPassport() {
passport.use(
new OpenIDConnectStrategy(
{
// ... other options
clientID: appId,
clientSecret: appSecret,
callbackURL: '/callback',
scope: ['openid', 'offline_access', 'profile', 'email'],
}
// ... other options
)
);
// ... other options
}

Aqui está a lista de Escopos (Scopes) suportados e as Reivindicações (Claims) correspondentes:

openid

Nome da ReivindicaçãoTipoDescriçãoPrecisa de userinfo?
substringO identificador único do usuárioNão

profile

Nome da ReivindicaçãoTipoDescriçãoPrecisa de userinfo?
namestringO nome completo do usuárioNão
usernamestringO nome de usuário do usuárioNão
picturestringURL da foto de perfil do Usuário Final. Este URL DEVE referir-se a um arquivo de imagem (por exemplo, um arquivo de imagem PNG, JPEG ou GIF), em vez de uma página da Web contendo uma imagem. Note que este URL DEVE referenciar especificamente uma foto de perfil do Usuário Final adequada para exibição ao descrever o Usuário Final, em vez de uma foto arbitrária tirada pelo Usuário Final.Não
created_atnumberHora em que o Usuário Final foi criado. O tempo é representado como o número de milissegundos desde a época Unix (1970-01-01T00:00:00Z).Não
updated_atnumberHora em que as informações do Usuário Final foram atualizadas pela última vez. O tempo é representado como o número de milissegundos desde a época Unix (1970-01-01T00:00:00Z).Não

Outras reivindicações padrão incluem family_name, given_name, middle_name, nickname, preferred_username, profile, website, gender, birthdate, zoneinfo e locale também serão incluídas no escopo profile sem a necessidade de solicitar o endpoint userinfo. Uma diferença em relação às reivindicações acima é que essas reivindicações só serão retornadas quando seus valores não estiverem vazios, enquanto as reivindicações acima retornarão null se os valores estiverem vazios.

nota

Ao contrário das reivindicações padrão, as reivindicações created_at e updated_at estão usando milissegundos em vez de segundos.

email

Nome da ReivindicaçãoTipoDescriçãoPrecisa de userinfo?
emailstringO endereço de email do usuárioNão
email_verifiedbooleanSe o endereço de email foi verificadoNão

phone

Nome da ReivindicaçãoTipoDescriçãoPrecisa de userinfo?
phone_numberstringO número de telefone do usuárioNão
phone_number_verifiedbooleanSe o número de telefone foi verificadoNão

address

Por favor, consulte o OpenID Connect Core 1.0 para os detalhes da reivindicação de endereço.

custom_data

Nome da ReivindicaçãoTipoDescriçãoPrecisa de userinfo?
custom_dataobjectOs dados personalizados do usuárioSim

identities

Nome da ReivindicaçãoTipoDescriçãoPrecisa de userinfo?
identitiesobjectAs identidades vinculadas do usuárioSim
sso_identitiesarrayAs identidades SSO vinculadas do usuárioSim

urn:logto:scope:organizations

Nome da ReivindicaçãoTipoDescriçãoPrecisa de userinfo?
organizationsstring[]Os IDs das organizações às quais o usuário pertenceNão
organization_dataobject[]Os dados das organizações às quais o usuário pertenceSim

urn:logto:scope:organization_roles

Nome da ReivindicaçãoTipoDescriçãoPrecisa de userinfo?
organization_rolesstring[]Os papéis da organização aos quais o usuário pertence com o formato <organization_id>:<role_name>Não

Considerando o desempenho e o tamanho dos dados, se "Precisa de userinfo?" for "Sim", isso significa que a reivindicação não aparecerá no Token de ID, mas será retornada na resposta do endpoint userinfo.

Leituras adicionais

Fluxos do usuário final: fluxos de autenticação, fluxos de conta e fluxos de organização Configurar conectores Proteger sua API