From c28fef274e3653dff628e9eba1f759ce557cf267 Mon Sep 17 00:00:00 2001 From: mynona Date: Fri, 10 Oct 2025 22:01:16 +0200 Subject: [PATCH 01/10] Extended Swift package with new features test# --- Package.swift | 7 ++- .../Documentation.docc/Documentation.md | 20 +++++++ Sources/ImperialLinkedIn/LinkedIn.swift | 17 ++++++ Sources/ImperialLinkedIn/LinkedInAuth.swift | 24 +++++++++ .../LinkedInCallbackBody.swift | 19 +++++++ Sources/ImperialLinkedIn/LinkedInRouter.swift | 54 +++++++++++++++++++ Sources/ImperialLinkedIn/readme.md | 24 +++++++++ 7 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 Sources/ImperialLinkedIn/Documentation.docc/Documentation.md create mode 100644 Sources/ImperialLinkedIn/LinkedIn.swift create mode 100644 Sources/ImperialLinkedIn/LinkedInAuth.swift create mode 100644 Sources/ImperialLinkedIn/LinkedInCallbackBody.swift create mode 100644 Sources/ImperialLinkedIn/LinkedInRouter.swift create mode 100644 Sources/ImperialLinkedIn/readme.md diff --git a/Package.swift b/Package.swift index 6c77682..14b74b4 100755 --- a/Package.swift +++ b/Package.swift @@ -24,6 +24,7 @@ let package = Package( .library(name: "ImperialMicrosoft", targets: ["ImperialCore", "ImperialMicrosoft"]), .library(name: "ImperialMixcloud", targets: ["ImperialCore", "ImperialMixcloud"]), .library(name: "ImperialShopify", targets: ["ImperialCore", "ImperialShopify"]), + .library(name: "ImperialLinkedIn", targets: ["ImperialCore", "ImperialLinkedIn"]), .library( name: "Imperial", targets: [ @@ -41,12 +42,13 @@ let package = Package( "ImperialMicrosoft", "ImperialMixcloud", "ImperialShopify", + "ImperialLinkedIn", ] ), ], dependencies: [ - .package(url: "https://github.com/vapor/vapor.git", from: "4.114.1"), - .package(url: "https://github.com/vapor/jwt-kit.git", from: "5.1.2"), + .package(url: "https://github.com/vapor/vapor.git", from: "4.117.0"), + .package(url: "https://github.com/vapor/jwt-kit.git", from: "5.2.0"), ], targets: [ .target( @@ -70,6 +72,7 @@ let package = Package( .target(name: "ImperialMicrosoft", dependencies: ["ImperialCore"], swiftSettings: swiftSettings), .target(name: "ImperialMixcloud", dependencies: ["ImperialCore"], swiftSettings: swiftSettings), .target(name: "ImperialShopify", dependencies: ["ImperialCore"], swiftSettings: swiftSettings), + .target(name: "ImperialLinkedIn", dependencies: ["ImperialCore"], swiftSettings: swiftSettings), .testTarget( name: "ImperialTests", dependencies: [ diff --git a/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md b/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md new file mode 100644 index 0000000..7022c45 --- /dev/null +++ b/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md @@ -0,0 +1,20 @@ +# ``ImperialLinkedIn`` + +Federated Authentication with linkedin for Vapor. + +## Overview + +### Linkedin setup + +**Register your app on LinkedIn Developer Portal** + - Add the product: **Sign In with LinkedIn** + - Set your redirect URI (e.g., `https://yourdomain.com/auth/linkedin/callback`) + - Ensure scopes: `openid`, `profile`, `email` + +### Imperial Integration + +You can use Keycloak with the `ImperialLinkedIn` package. This expects two environment variables: + +* `LINKEDIN_CLIENT_ID=your_client_id` +* `LINKEDIN_CLIENT_SECRET=your_client_secret` + diff --git a/Sources/ImperialLinkedIn/LinkedIn.swift b/Sources/ImperialLinkedIn/LinkedIn.swift new file mode 100644 index 0000000..d9a6bf2 --- /dev/null +++ b/Sources/ImperialLinkedIn/LinkedIn.swift @@ -0,0 +1,17 @@ +@_exported import ImperialCore +import Vapor + +public struct LinkedIn: FederatedService { + @discardableResult + public init( + routes: some RoutesBuilder, + authenticate: String, + authenticateCallback: (@Sendable (Request) async throws -> Void)?, + callback: String, + scope: [String] = ["openid","profile","email"], + completion: @escaping @Sendable (Request, String) async throws -> some AsyncResponseEncodable + ) throws { + try LinkedInRouter(callback: callback, scope: scope, completion: completion) + .configureRoutes(withAuthURL: authenticate, authenticateCallback: authenticateCallback, on: routes) + } +} diff --git a/Sources/ImperialLinkedIn/LinkedInAuth.swift b/Sources/ImperialLinkedIn/LinkedInAuth.swift new file mode 100644 index 0000000..dab5f4b --- /dev/null +++ b/Sources/ImperialLinkedIn/LinkedInAuth.swift @@ -0,0 +1,24 @@ +import Vapor + +struct LinkedInAuth: FederatedServiceTokens { + static let idEnvKey: String = "LINKEDIN_CLIENT_ID" + static let secretEnvKey: String = "LINKEDIN_CLIENT_SECRET" + let clientID: String + let clientSecret: String + + init() throws { + guard + let clientID = Environment.get(Self.idEnvKey) + else { + throw ImperialError.missingEnvVar(Self.idEnvKey) + } + self.clientID = clientID + + guard + let clientSecret = Environment.get(Self.secretEnvKey) + else { + throw ImperialError.missingEnvVar(Self.secretEnvKey) + } + self.clientSecret = clientSecret + } +} diff --git a/Sources/ImperialLinkedIn/LinkedInCallbackBody.swift b/Sources/ImperialLinkedIn/LinkedInCallbackBody.swift new file mode 100644 index 0000000..f2a8da3 --- /dev/null +++ b/Sources/ImperialLinkedIn/LinkedInCallbackBody.swift @@ -0,0 +1,19 @@ +import Vapor + +struct LinkedInCallbackBody: Content { + let grantType: String = "authorization_code" + let code: String + let redirectURI: String + let clientId: String + let clientSecret: String + + static let defaultContentType: HTTPMediaType = .urlEncodedForm + + enum CodingKeys: String, CodingKey { + case grantType = "grant_type" + case code + case redirectURI = "redirect_uri" + case clientId = "client_id" + case clientSecret = "client_secret" + } +} diff --git a/Sources/ImperialLinkedIn/LinkedInRouter.swift b/Sources/ImperialLinkedIn/LinkedInRouter.swift new file mode 100644 index 0000000..5b0d543 --- /dev/null +++ b/Sources/ImperialLinkedIn/LinkedInRouter.swift @@ -0,0 +1,54 @@ +import Foundation +import Vapor + +struct LinkedInRouter: FederatedServiceRouter { + let tokens: any FederatedServiceTokens + let callbackCompletion: @Sendable (Request, String) async throws -> any AsyncResponseEncodable + let scope: [String] + let callbackURL: String + let accessTokenURL: String = "https://www.linkedin.com/oauth/v2/accessToken" + let callbackHeaders: HTTPHeaders = { + var headers = HTTPHeaders() + headers.contentType = .urlEncodedForm + return headers + }() + + init( + callback: String, scope: [String], completion: @escaping @Sendable (Request, String) async throws -> some AsyncResponseEncodable + ) throws { + self.tokens = try LinkedInAuth() + self.callbackURL = callback + self.callbackCompletion = completion + self.scope = scope + } + + func authURL(_ request: Request) throws -> String { + var components = URLComponents() + components.scheme = "https" + components.host = "www.linkedin.com" + components.path = "/oauth/v2/authorization" + components.queryItems = [ + URLQueryItem(name: "response_type", value: "code"), + URLQueryItem(name: "client_id", value: tokens.clientID), + URLQueryItem(name: "redirect_uri", value: callbackURL), + URLQueryItem(name: "scope", value: scope.joined(separator: " ")) + ] + + guard let url = components.url else { + throw Abort(.internalServerError) + } + print("====") + print(url.absoluteString) + + return url.absoluteString + } + + func callbackBody(with code: String) -> any AsyncResponseEncodable { + LinkedInCallbackBody( + code: code, + redirectURI: callbackURL, + clientId: tokens.clientID, + clientSecret: tokens.clientSecret + ) + } +} diff --git a/Sources/ImperialLinkedIn/readme.md b/Sources/ImperialLinkedIn/readme.md new file mode 100644 index 0000000..c944895 --- /dev/null +++ b/Sources/ImperialLinkedIn/readme.md @@ -0,0 +1,24 @@ +# LinkedIn Sign-In Extension for Imperial + +This package extends [Imperial](https://github.com/vapor-community/Imperial) with support for **Sign In with LinkedIn** using the latest OpenID Connect-based API. + +## 🔧 Requirements + +- Vapor 4+ +- Imperial 2.1.0+ +- LinkedIn Developer Account +- Environment variables: + - `LINKEDIN_CLIENT_ID` + - `LINKEDIN_CLIENT_SECRET` + +## 🚀 Setup + +1. **Register your app on LinkedIn Developer Portal** + - Add the product: **Sign In with LinkedIn** + - Set your redirect URI (e.g., `https://yourdomain.com/auth/linkedin/callback`) + - Ensure scopes: `openid`, `profile`, `email` + +2. **Add environment variables** + ```bash + export LINKEDIN_CLIENT_ID=your_client_id + export LINKEDIN_CLIENT_SECRET=your_client_secret From e7352a39683cd2240e991ffb8a673cf16925d194 Mon Sep 17 00:00:00 2001 From: mynona Date: Fri, 10 Oct 2025 22:14:20 +0200 Subject: [PATCH 02/10] delete readme --- Sources/ImperialLinkedIn/readme.md | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 Sources/ImperialLinkedIn/readme.md diff --git a/Sources/ImperialLinkedIn/readme.md b/Sources/ImperialLinkedIn/readme.md deleted file mode 100644 index c944895..0000000 --- a/Sources/ImperialLinkedIn/readme.md +++ /dev/null @@ -1,24 +0,0 @@ -# LinkedIn Sign-In Extension for Imperial - -This package extends [Imperial](https://github.com/vapor-community/Imperial) with support for **Sign In with LinkedIn** using the latest OpenID Connect-based API. - -## 🔧 Requirements - -- Vapor 4+ -- Imperial 2.1.0+ -- LinkedIn Developer Account -- Environment variables: - - `LINKEDIN_CLIENT_ID` - - `LINKEDIN_CLIENT_SECRET` - -## 🚀 Setup - -1. **Register your app on LinkedIn Developer Portal** - - Add the product: **Sign In with LinkedIn** - - Set your redirect URI (e.g., `https://yourdomain.com/auth/linkedin/callback`) - - Ensure scopes: `openid`, `profile`, `email` - -2. **Add environment variables** - ```bash - export LINKEDIN_CLIENT_ID=your_client_id - export LINKEDIN_CLIENT_SECRET=your_client_secret From 208c6cd5ea599aa9d029b5b9492f3295003fda70 Mon Sep 17 00:00:00 2001 From: mynona Date: Fri, 10 Oct 2025 22:22:00 +0200 Subject: [PATCH 03/10] add test --- Package.swift | 1 + Tests/ImperialTests/ImperialTests.swift | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/Package.swift b/Package.swift index 14b74b4..6f2caa7 100755 --- a/Package.swift +++ b/Package.swift @@ -90,6 +90,7 @@ let package = Package( .target(name: "ImperialMicrosoft"), .target(name: "ImperialMixcloud"), .target(name: "ImperialShopify"), + .target(name: "ImperialLinkedIn"), .product(name: "VaporTesting", package: "vapor"), ], resources: [ diff --git a/Tests/ImperialTests/ImperialTests.swift b/Tests/ImperialTests/ImperialTests.swift index 85e7bf9..cad9e1b 100644 --- a/Tests/ImperialTests/ImperialTests.swift +++ b/Tests/ImperialTests/ImperialTests.swift @@ -11,6 +11,7 @@ import ImperialImgur import ImperialKeycloak import ImperialMicrosoft import ImperialMixcloud +import ImperialLinkedIn import Testing import VaporTesting @@ -218,6 +219,26 @@ struct ImperialTests { } } + @Test("LinkedIn Route") + func linkedInRoute() async throws { + try await withApp(service: LinkedIn.self) { app in + try await app.test( + .GET, authURL, + afterResponse: { res async throws in + #expect(res.status == .seeOther) + } + ) + + try await app.test( + .GET, "\(callbackURL)?code=123", + afterResponse: { res async throws in + // TODO: test this route + #expect(res.status != .notFound) + } + ) + } + } + @Test("Keycloak Route") func keycloakRoute() async throws { try await withApp(service: Keycloak.self) { app in From 760d625fba9556f3ee2894b7cddb0134975ca9e6 Mon Sep 17 00:00:00 2001 From: mynona Date: Fri, 10 Oct 2025 22:44:02 +0200 Subject: [PATCH 04/10] documentation --- .../Documentation.docc/Documentation.md | 90 +++++++++++++++++-- 1 file changed, 83 insertions(+), 7 deletions(-) diff --git a/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md b/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md index 7022c45..97012bc 100644 --- a/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md +++ b/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md @@ -1,20 +1,96 @@ # ``ImperialLinkedIn`` -Federated Authentication with linkedin for Vapor. +Federated Authentication with LinkedIn for Vapor. ## Overview ### Linkedin setup -**Register your app on LinkedIn Developer Portal** - - Add the product: **Sign In with LinkedIn** - - Set your redirect URI (e.g., `https://yourdomain.com/auth/linkedin/callback`) - - Ensure scopes: `openid`, `profile`, `email` +1. Register your app on the LinkedIn developer portal +2. Add the product "Sign in with LinkedIn" +3. Set your redirect URI (e.g., `https://yourdomain.com/auth/linkedin/callback`) +4. Set scopes `openid`, `profile` and `email` -### Imperial Integration -You can use Keycloak with the `ImperialLinkedIn` package. This expects two environment variables: +### Linkedin API + +[Developer documentation](https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/sign-in-with-linkedin-v2?context=linkedin%2Fconsumer%2Fcontext) + + +### Expected environment variables + +Imperial expects two environment variables: * `LINKEDIN_CLIENT_ID=your_client_id` * `LINKEDIN_CLIENT_SECRET=your_client_secret` +### Integration example + +``` +Import Vapor + +struct LinkedInUserInfo: Content { + let sub: String + let given_name: String? + let family_name: String? + let picture: String? + let email: String + let email_verified: Bool? + let locale: LinkedInLocale? +} + +struct LinkedInLocale: Content { + let country: String? + let language: String? +} + +struct LinkedInImperialRouter: RouteCollection { + + func boot(routes: RoutesBuilder) throws { + + try routes.oAuth( + from: LinkedIn.self, + authenticate: "auth2/linkedin/", + callback: yourCustomCallbackPath, + scope: ["openid","profile","email"], + completion: processLinkedInLogin + ) + } + + func processLinkedInLogin(request: Request, token: String) async throws -> Response { + + let userInfo = try await LinkedIn.getUser(on: request) + + // Your own user management implementation + var user = try await User + .query(on: request.db) + .filter(\.$username == userInfo.sub) + .first() + + // You might update and save your user data + +} + +extension LinkedIn { + + static func getUser(on request: Request) async throws -> LinkedInUserInfo { + var headers = HTTPHeaders() + headers.bearerAuthorization = try BearerAuthorization(token: request.accessToken) + + let userInfoURL: URI = "https://api.linkedin.com/v2/userinfo" + let response = try await request.client.get(userInfoURL, headers: headers) + print(response) + let userInfo = try response.content.decode(LinkedInUserInfo.self) + + request.logger.debug("\(userInfo)") + + guard response.status == .ok else { + throw Abort(.unauthorized) + } + + return userInfo + } +} +``` + + From fc0f964213baf33e96e0bd9204443fda43307026 Mon Sep 17 00:00:00 2001 From: mynona Date: Fri, 10 Oct 2025 23:19:52 +0200 Subject: [PATCH 05/10] swift format --- Sources/ImperialLinkedIn/LinkedIn.swift | 2 +- Sources/ImperialLinkedIn/LinkedInAuth.swift | 40 +++++++++---------- Sources/ImperialLinkedIn/LinkedInRouter.swift | 6 +-- Tests/ImperialTests/ImperialTests.swift | 36 ++++++++--------- 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/Sources/ImperialLinkedIn/LinkedIn.swift b/Sources/ImperialLinkedIn/LinkedIn.swift index d9a6bf2..96552af 100644 --- a/Sources/ImperialLinkedIn/LinkedIn.swift +++ b/Sources/ImperialLinkedIn/LinkedIn.swift @@ -8,7 +8,7 @@ public struct LinkedIn: FederatedService { authenticate: String, authenticateCallback: (@Sendable (Request) async throws -> Void)?, callback: String, - scope: [String] = ["openid","profile","email"], + scope: [String] = ["openid", "profile", "email"], completion: @escaping @Sendable (Request, String) async throws -> some AsyncResponseEncodable ) throws { try LinkedInRouter(callback: callback, scope: scope, completion: completion) diff --git a/Sources/ImperialLinkedIn/LinkedInAuth.swift b/Sources/ImperialLinkedIn/LinkedInAuth.swift index dab5f4b..d798cf8 100644 --- a/Sources/ImperialLinkedIn/LinkedInAuth.swift +++ b/Sources/ImperialLinkedIn/LinkedInAuth.swift @@ -1,24 +1,24 @@ import Vapor struct LinkedInAuth: FederatedServiceTokens { - static let idEnvKey: String = "LINKEDIN_CLIENT_ID" - static let secretEnvKey: String = "LINKEDIN_CLIENT_SECRET" - let clientID: String - let clientSecret: String - - init() throws { - guard - let clientID = Environment.get(Self.idEnvKey) - else { - throw ImperialError.missingEnvVar(Self.idEnvKey) - } - self.clientID = clientID - - guard - let clientSecret = Environment.get(Self.secretEnvKey) - else { - throw ImperialError.missingEnvVar(Self.secretEnvKey) - } - self.clientSecret = clientSecret - } + static let idEnvKey: String = "LINKEDIN_CLIENT_ID" + static let secretEnvKey: String = "LINKEDIN_CLIENT_SECRET" + let clientID: String + let clientSecret: String + + init() throws { + guard + let clientID = Environment.get(Self.idEnvKey) + else { + throw ImperialError.missingEnvVar(Self.idEnvKey) + } + self.clientID = clientID + + guard + let clientSecret = Environment.get(Self.secretEnvKey) + else { + throw ImperialError.missingEnvVar(Self.secretEnvKey) + } + self.clientSecret = clientSecret + } } diff --git a/Sources/ImperialLinkedIn/LinkedInRouter.swift b/Sources/ImperialLinkedIn/LinkedInRouter.swift index 5b0d543..66640db 100644 --- a/Sources/ImperialLinkedIn/LinkedInRouter.swift +++ b/Sources/ImperialLinkedIn/LinkedInRouter.swift @@ -31,14 +31,14 @@ struct LinkedInRouter: FederatedServiceRouter { URLQueryItem(name: "response_type", value: "code"), URLQueryItem(name: "client_id", value: tokens.clientID), URLQueryItem(name: "redirect_uri", value: callbackURL), - URLQueryItem(name: "scope", value: scope.joined(separator: " ")) + URLQueryItem(name: "scope", value: scope.joined(separator: " ")), ] guard let url = components.url else { throw Abort(.internalServerError) } - print("====") - print(url.absoluteString) + print("====") + print(url.absoluteString) return url.absoluteString } diff --git a/Tests/ImperialTests/ImperialTests.swift b/Tests/ImperialTests/ImperialTests.swift index cad9e1b..42395cd 100644 --- a/Tests/ImperialTests/ImperialTests.swift +++ b/Tests/ImperialTests/ImperialTests.swift @@ -219,25 +219,25 @@ struct ImperialTests { } } - @Test("LinkedIn Route") - func linkedInRoute() async throws { - try await withApp(service: LinkedIn.self) { app in - try await app.test( - .GET, authURL, - afterResponse: { res async throws in - #expect(res.status == .seeOther) - } - ) + @Test("LinkedIn Route") + func linkedInRoute() async throws { + try await withApp(service: LinkedIn.self) { app in + try await app.test( + .GET, authURL, + afterResponse: { res async throws in + #expect(res.status == .seeOther) + } + ) - try await app.test( - .GET, "\(callbackURL)?code=123", - afterResponse: { res async throws in - // TODO: test this route - #expect(res.status != .notFound) - } - ) - } - } + try await app.test( + .GET, "\(callbackURL)?code=123", + afterResponse: { res async throws in + // TODO: test this route + #expect(res.status != .notFound) + } + ) + } + } @Test("Keycloak Route") func keycloakRoute() async throws { From f018bcd289af4caa0f572ae138530de04befe8d7 Mon Sep 17 00:00:00 2001 From: mynona Date: Fri, 10 Oct 2025 23:23:30 +0200 Subject: [PATCH 06/10] Update .env.testing Add LINKEDIN --- .env.testing | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.env.testing b/.env.testing index c8aa3f3..76cbbc3 100644 --- a/.env.testing +++ b/.env.testing @@ -41,4 +41,7 @@ MIXCLOUD_CLIENT_ID=test MIXCLOUD_CLIENT_SECRET=test SHOPIFY_CLIENT_ID=test -SHOPIFY_CLIENT_SECRET=test \ No newline at end of file +SHOPIFY_CLIENT_SECRET=test + +LINKEDIN_CLIENT_SECRET=test +LINKEDIN_CLIENT_ID=test From 55fa6b09ef11084f2dcf9b18b89e33ee6ad6749a Mon Sep 17 00:00:00 2001 From: mynona Date: Fri, 10 Oct 2025 23:33:38 +0200 Subject: [PATCH 07/10] Update Sources/ImperialLinkedIn/Documentation.docc/Documentation.md Co-authored-by: Francesco Paolo Severino <96546612+fpseverino@users.noreply.github.com> --- Sources/ImperialLinkedIn/Documentation.docc/Documentation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md b/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md index 97012bc..d9cfc64 100644 --- a/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md +++ b/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md @@ -4,7 +4,7 @@ Federated Authentication with LinkedIn for Vapor. ## Overview -### Linkedin setup +### LinkedIn setup 1. Register your app on the LinkedIn developer portal 2. Add the product "Sign in with LinkedIn" From 50e542a65f2fa0a403072272c3f3e6fddf68d0a9 Mon Sep 17 00:00:00 2001 From: mynona Date: Fri, 10 Oct 2025 23:36:55 +0200 Subject: [PATCH 08/10] Update Sources/ImperialLinkedIn/Documentation.docc/Documentation.md Co-authored-by: Francesco Paolo Severino <96546612+fpseverino@users.noreply.github.com> --- Sources/ImperialLinkedIn/Documentation.docc/Documentation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md b/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md index d9cfc64..96fcdaa 100644 --- a/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md +++ b/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md @@ -26,7 +26,7 @@ Imperial expects two environment variables: ### Integration example -``` +```swift Import Vapor struct LinkedInUserInfo: Content { From 139d4599917c51ed55cf924159eb8cee9d4349f3 Mon Sep 17 00:00:00 2001 From: mynona Date: Fri, 10 Oct 2025 23:37:05 +0200 Subject: [PATCH 09/10] Update Sources/ImperialLinkedIn/Documentation.docc/Documentation.md Co-authored-by: Francesco Paolo Severino <96546612+fpseverino@users.noreply.github.com> --- Sources/ImperialLinkedIn/Documentation.docc/Documentation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md b/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md index 96fcdaa..4c663f7 100644 --- a/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md +++ b/Sources/ImperialLinkedIn/Documentation.docc/Documentation.md @@ -12,7 +12,7 @@ Federated Authentication with LinkedIn for Vapor. 4. Set scopes `openid`, `profile` and `email` -### Linkedin API +### LinkedIn API [Developer documentation](https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/sign-in-with-linkedin-v2?context=linkedin%2Fconsumer%2Fcontext) From 1e9308e5e827563163b7e7692aaeaa5851e32699 Mon Sep 17 00:00:00 2001 From: mynona Date: Fri, 10 Oct 2025 23:44:01 +0200 Subject: [PATCH 10/10] remove print --- Sources/ImperialLinkedIn/LinkedInRouter.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Sources/ImperialLinkedIn/LinkedInRouter.swift b/Sources/ImperialLinkedIn/LinkedInRouter.swift index 66640db..e7989f7 100644 --- a/Sources/ImperialLinkedIn/LinkedInRouter.swift +++ b/Sources/ImperialLinkedIn/LinkedInRouter.swift @@ -37,8 +37,6 @@ struct LinkedInRouter: FederatedServiceRouter { guard let url = components.url else { throw Abort(.internalServerError) } - print("====") - print(url.absoluteString) return url.absoluteString }