Skip to content

Commit

Permalink
feat: Feathers Cloud Auth basic integration
Browse files Browse the repository at this point in the history
  • Loading branch information
daffl committed Sep 27, 2024
1 parent bb9cb2a commit 34d377a
Show file tree
Hide file tree
Showing 9 changed files with 5,168 additions and 21,789 deletions.
2 changes: 1 addition & 1 deletion feathers-chat-ts/config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"public": "../public/",
"origins": [
"http://localhost:3030",
"http://localhost:3000"
"http://localhost:3001"
],
"paginate": {
"default": 10,
Expand Down
91 changes: 88 additions & 3 deletions feathers-chat-ts/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions feathers-chat-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"migrate:make": "knex migrate:make"
},
"dependencies": {
"@featherscloud/auth": "^0.6.5",
"@feathersjs/adapter-commons": "^5.0.28",
"@feathersjs/authentication": "^5.0.28",
"@feathersjs/authentication-client": "^5.0.28",
Expand Down
62 changes: 60 additions & 2 deletions feathers-chat-ts/src/authentication.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,74 @@
import type { Params } from '@feathersjs/feathers'
import { AuthenticationService, JWTStrategy } from '@feathersjs/authentication'
import { AuthenticationParams, AuthenticationRequest, AuthenticationService, JWTStrategy } from '@feathersjs/authentication'
import { CloudAuthUser, createVerifier } from '@featherscloud/auth'
import { LocalStrategy } from '@feathersjs/authentication-local'
import { oauth, OAuthStrategy } from '@feathersjs/authentication-oauth'
import type { OAuthProfile } from '@feathersjs/authentication-oauth'
import type { Application } from './declarations'
import { NotAuthenticated } from '@feathersjs/errors'

declare module './declarations' {
interface ServiceTypes {
authentication: AuthenticationService
}
}

const verifier = createVerifier({
appId: 'did:key:z6Mksc9d7DyrKFpyNcZHUy5G78vGFaFwdAuzJSBd9HHM9Msk',
})

class CloudAuthStrategy extends JWTStrategy {
async findUser (cloudUser: CloudAuthUser, params: AuthenticationParams) {
const result = await this.entityService.find({
...params,
query: {
email: cloudUser.email
}
})
const [user] = Array.isArray(result) ? result : result.data;

if (!user) {
return this.createUser(cloudUser, params);
}

return user
}

async createUser (user: CloudAuthUser, params: AuthenticationParams) {
const entity = await this.entityService.create({
email: user.email
}, params);

return entity;
}

async authenticate(authentication: AuthenticationRequest, params: AuthenticationParams) {
const { accessToken } = authentication;
const { entity } = this.configuration;
if (!accessToken) {
throw new NotAuthenticated('No access token');
}
const verified = await verifier.verify(accessToken);
const result = {
accessToken,
authentication: {
strategy: this.name || 'jwt',
accessToken,
...verified
}
};

if (entity === null || verified.user === null) {
return result;
}

return {
...result,
[entity]: await this.findUser(verified.user, params)
};
}
}

class GitHubStrategy extends OAuthStrategy {
async getEntityData(profile: OAuthProfile, existing: any, params: Params) {
const baseData = await super.getEntityData(profile, existing, params)
Expand All @@ -28,7 +86,7 @@ class GitHubStrategy extends OAuthStrategy {
export const authentication = (app: Application) => {
const authentication = new AuthenticationService(app)

authentication.register('jwt', new JWTStrategy())
authentication.register('jwt', new CloudAuthStrategy())
authentication.register('local', new LocalStrategy())
authentication.register('github', new GitHubStrategy())

Expand Down
29 changes: 27 additions & 2 deletions feathers-chat-ts/src/client.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// For more information about this file see https://dove.feathersjs.com/guides/cli/client.html
import { feathers } from '@feathersjs/feathers'
import type { TransportConnection, Application } from '@feathersjs/feathers'
import authenticationClient from '@feathersjs/authentication-client'
import authenticationClient, { AuthenticationClient } from '@feathersjs/authentication-client'
import type { AuthenticationClientOptions } from '@feathersjs/authentication-client'

import { messageClient } from './services/messages/messages.shared'
Expand All @@ -10,6 +10,8 @@ export type { Message, MessageData, MessageQuery, MessagePatch } from './service
import { userClient } from './services/users/users.shared'
export type { User, UserData, UserQuery, UserPatch } from './services/users/users.shared'

import { createClient as createAuthClient, LoginRequiredError } from '@featherscloud/auth'

export interface Configuration {
connection: TransportConnection<ServiceTypes>
}
Expand All @@ -18,6 +20,26 @@ export interface ServiceTypes {}

export type ClientApplication = Application<ServiceTypes, Configuration>

const auth = createAuthClient({
appId: 'did:key:z6Mksc9d7DyrKFpyNcZHUy5G78vGFaFwdAuzJSBd9HHM9Msk',
tokenUrl: 'http://localhost:8787/token',
})

class CloudAuthClient extends AuthenticationClient {
async getAccessToken() {
try {
const token = await auth.getAccessToken()
return token
} catch (error: unknown) {
if (error instanceof LoginRequiredError) {
window.location.href = await auth.getLoginUrl(error)
}

throw error
}
}
}

/**
* Returns a typed client for the feathers-chat app.
*
Expand All @@ -33,7 +55,10 @@ export const createClient = <Configuration = any>(
const client: ClientApplication = feathers()

client.configure(connection)
client.configure(authenticationClient(authenticationOptions))
client.configure(authenticationClient({
Authentication: CloudAuthClient,
...authenticationOptions
}))
client.set('connection', connection)

client.configure(userClient)
Expand Down
Loading

0 comments on commit 34d377a

Please sign in to comment.